Changeset 108:889d0c289d19 in lemon-main
- Timestamp:
- 03/25/08 16:36:44 (17 years ago)
- Branch:
- default
- Children:
- 109:abddaa08b507, 112:d2ee5e7f00ef
- Phase:
- public
- Files:
-
- 5 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
lemon/Makefile.am
r106 r108 18 18 lemon_HEADERS += \ 19 19 lemon/arg_parser.h \ 20 lemon/assert.h \ 20 21 lemon/bfs.h \ 21 22 lemon/bin_heap.h \ -
lemon/arg_parser.h
r95 r108 27 27 #include <sstream> 28 28 #include <algorithm> 29 #include <lemon/ error.h>29 #include <lemon/assert.h> 30 30 31 31 ///\ingroup misc -
lemon/assert.h
r66 r108 17 17 */ 18 18 19 #ifndef LEMON_ ERROR_H20 #define LEMON_ ERROR_H19 #ifndef LEMON_ASSERT_H 20 #define LEMON_ASSERT_H 21 21 22 22 /// \ingroup exceptions 23 23 /// \file 24 /// \brief Basic exception classes and error handling. 25 26 #include <exception> 27 #include <string> 28 #include <sstream> 29 #include <iostream> 30 #include <cstdlib> 31 #include <memory> 24 /// \brief Extended assertion handling 25 26 #include <lemon/error.h> 32 27 33 28 namespace lemon { 34 29 35 /// \addtogroup exceptions36 30 /// @{ 37 31 38 /// \brief Exception safe wrapper class. 39 /// 40 /// Exception safe wrapper class to implement the members of exceptions. 41 template <typename _Type> 42 class ExceptionMember { 43 public: 44 typedef _Type Type; 45 46 ExceptionMember() throw() { 47 try { 48 ptr.reset(new Type()); 49 } catch (...) {} 50 } 51 52 ExceptionMember(const Type& type) throw() { 53 try { 54 ptr.reset(new Type()); 55 if (ptr.get() == 0) return; 56 *ptr = type; 57 } catch (...) {} 58 } 59 60 ExceptionMember(const ExceptionMember& copy) throw() { 61 try { 62 if (!copy.valid()) return; 63 ptr.reset(new Type()); 64 if (ptr.get() == 0) return; 65 *ptr = copy.get(); 66 } catch (...) {} 67 } 68 69 ExceptionMember& operator=(const ExceptionMember& copy) throw() { 70 if (ptr.get() == 0) return; 71 try { 72 if (!copy.valid()) return; 73 *ptr = copy.get(); 74 } catch (...) {} 75 } 76 77 void set(const Type& type) throw() { 78 if (ptr.get() == 0) return; 79 try { 80 *ptr = type; 81 } catch (...) {} 82 } 83 84 const Type& get() const { 85 return *ptr; 86 } 87 88 bool valid() const throw() { 89 return ptr.get() != 0; 90 } 91 92 private: 93 std::auto_ptr<_Type> ptr; 94 }; 95 96 /// Exception-safe convenient "error message" class. 97 98 /// Helper class which provides a convenient ostream-like (operator << 99 /// based) interface to create a string message. Mostly useful in 100 /// exception classes (therefore the name). 101 class ErrorMessage { 32 ///\e 33 class AssertionFailedError : public LogicError { 102 34 protected: 103 ///\e 104 105 ///\todo The good solution is boost::shared_ptr... 106 /// 107 mutable std::auto_ptr<std::ostringstream> buf; 108 109 ///\e 110 bool init() throw() { 111 try { 112 buf.reset(new std::ostringstream); 113 } 114 catch(...) { 115 buf.reset(); 116 } 117 return buf.get(); 118 } 119 120 public: 121 122 ///\e 123 ErrorMessage() throw() { init(); } 124 125 ErrorMessage(const ErrorMessage& em) throw() : buf(em.buf) { } 126 127 ///\e 128 ErrorMessage(const char *msg) throw() { 129 init(); 130 *this << msg; 131 } 132 133 ///\e 134 ErrorMessage(const std::string &msg) throw() { 135 init(); 136 *this << msg; 137 } 138 139 ///\e 140 template <typename T> 141 ErrorMessage& operator<<(const T &t) throw() { 142 if( ! buf.get() ) return *this; 143 144 try { 145 *buf << t; 146 } 147 catch(...) { 148 buf.reset(); 149 } 150 return *this; 151 } 152 153 ///\e 154 const char* message() throw() { 155 if( ! buf.get() ) return 0; 156 157 const char* mes = 0; 158 try { 159 mes = buf->str().c_str(); 160 } 161 catch(...) {} 162 return mes; 163 } 164 165 }; 166 167 /// Generic exception class. 168 169 /// Base class for exceptions used in LEMON. 170 /// 171 class Exception : public std::exception { 172 public: 173 ///\e 174 Exception() {} 175 ///\e 176 virtual ~Exception() throw() {} 177 ///\e 178 virtual const char* what() const throw() { 179 return "lemon::Exception"; 180 } 181 }; 182 183 /// One of the two main subclasses of \ref Exception. 184 185 /// Logic errors represent problems in the internal logic of a program; 186 /// in theory, these are preventable, and even detectable before the 187 /// program runs (e.g. violations of class invariants). 188 /// 189 /// A typical example for this is \ref UninitializedParameter. 190 class LogicError : public Exception { 191 public: 192 virtual const char* what() const throw() { 193 return "lemon::LogicError"; 194 } 195 }; 196 197 /// \ref Exception for uninitialized parameters. 198 199 /// This error represents problems in the initialization 200 /// of the parameters of the algorithms. 201 class UninitializedParameter : public LogicError { 202 public: 203 virtual const char* what() const throw() { 204 return "lemon::UninitializedParameter"; 205 } 206 }; 207 208 209 /// One of the two main subclasses of \ref Exception. 210 211 /// Runtime errors represent problems outside the scope of a program; 212 /// they cannot be easily predicted and can generally only be caught 213 /// as the program executes. 214 class RuntimeError : public Exception { 215 public: 216 virtual const char* what() const throw() { 217 return "lemon::RuntimeError"; 218 } 219 }; 220 221 ///\e 222 class RangeError : public RuntimeError { 223 public: 224 virtual const char* what() const throw() { 225 return "lemon::RangeError"; 226 } 227 }; 228 229 ///\e 230 class IoError : public RuntimeError { 231 public: 232 virtual const char* what() const throw() { 233 return "lemon::IoError"; 234 } 235 }; 236 237 ///\e 238 class DataFormatError : public IoError { 239 protected: 240 ExceptionMember<std::string> _message; 241 ExceptionMember<std::string> _file; 35 const char *_assertion; 36 const char *_file; 242 37 int _line; 38 const char *_function; 39 const char *_message; 243 40 244 41 mutable ExceptionMember<std::string> _message_holder; 245 42 public: 246 247 DataFormatError(const DataFormatError &dfe) : 248 IoError(dfe), _message(dfe._message), _file(dfe._file), 249 _line(dfe._line) {} 250 251 ///\e 252 explicit DataFormatError(const char *the_message) 253 : _message(the_message), _line(0) {} 254 255 ///\e 256 DataFormatError(const std::string &file_name, int line_num, 257 const char *the_message) 258 : _message(the_message), _line(line_num) { file(file_name); } 259 260 ///\e 261 void line(int ln) { _line = ln; } 262 ///\e 263 void message(const std::string& msg) { _message.set(msg); } 264 ///\e 265 void file(const std::string &fl) { _file.set(fl); } 266 43 ///\e 44 AssertionFailedError(const char *file, int line, const char *function, 45 const char *msg, const char *assertion = 0) : 46 _assertion(assertion), _file(file), _line(line), 47 _function(function), _message(msg) {} 48 49 ///\e 50 const char* assertion() const { return _assertion; } 51 ///\e 52 const char* message() const { return _message; } 53 ///\e 54 const char* file() const { return _file; } 55 ///\e 56 const char* function() const { return _function; } 267 57 ///\e 268 58 int line() const { return _line; } 269 ///\e 270 const char* message() const { 271 if (_message.valid() && !_message.get().empty()) { 272 return _message.get().c_str(); 273 } else { 274 return 0; 275 } 276 } 277 278 /// \brief Returns the filename. 279 /// 280 /// Returns \e null if the filename was not specified. 281 const char* file() const { 282 if (_file.valid() && !_file.get().empty()) { 283 return _file.get().c_str(); 284 } else { 285 return 0; 286 } 287 } 288 289 ///\e 59 60 290 61 virtual const char* what() const throw() { 291 62 try { 292 63 std::ostringstream ostr; 293 ostr << "lemon:DataFormatError" << ": "; 294 if (message()) ostr << message(); 295 if( file() || line() != 0 ) { 296 ostr << " ("; 297 if( file() ) ostr << "in file '" << file() << "'"; 298 if( file() && line() != 0 ) ostr << " "; 299 if( line() != 0 ) ostr << "at line " << line(); 300 ostr << ")"; 301 } 302 _message_holder.set(ostr.str()); 303 } 304 catch (...) {} 305 if( _message_holder.valid()) return _message_holder.get().c_str(); 306 return "lemon:DataFormatError"; 307 } 308 309 virtual ~DataFormatError() throw() {} 310 }; 311 312 ///\e 313 class FileOpenError : public IoError { 314 protected: 315 ExceptionMember<std::string> _file; 316 317 mutable ExceptionMember<std::string> _message_holder; 318 public: 319 320 FileOpenError(const FileOpenError &foe) : 321 IoError(foe), _file(foe._file) {} 322 323 ///\e 324 explicit FileOpenError(const std::string& fl) 325 : _file(fl) {} 326 327 328 ///\e 329 void file(const std::string &fl) { _file.set(fl); } 330 331 /// \brief Returns the filename. 332 /// 333 /// Returns \e null if the filename was not specified. 334 const char* file() const { 335 if (_file.valid() && !_file.get().empty()) { 336 return _file.get().c_str(); 337 } else { 338 return 0; 339 } 340 } 341 342 ///\e 343 virtual const char* what() const throw() { 344 try { 345 std::ostringstream ostr; 346 ostr << "lemon::FileOpenError" << ": "; 347 ostr << "Cannot open file - " << file(); 348 _message_holder.set(ostr.str()); 349 } 350 catch (...) {} 351 if( _message_holder.valid()) return _message_holder.get().c_str(); 352 return "lemon::FileOpenError"; 353 } 354 virtual ~FileOpenError() throw() {} 355 }; 356 357 class IoParameterError : public IoError { 358 protected: 359 ExceptionMember<std::string> _message; 360 ExceptionMember<std::string> _file; 361 362 mutable ExceptionMember<std::string> _message_holder; 363 public: 364 365 IoParameterError(const IoParameterError &ile) : 366 IoError(ile), _message(ile._message), _file(ile._file) {} 367 368 ///\e 369 explicit IoParameterError(const char *the_message) 370 : _message(the_message) {} 371 372 ///\e 373 IoParameterError(const char *file_name, const char *the_message) 374 : _message(the_message), _file(file_name) {} 375 376 ///\e 377 void message(const std::string& msg) { _message.set(msg); } 378 ///\e 379 void file(const std::string &fl) { _file.set(fl); } 380 381 ///\e 382 const char* message() const { 383 if (_message.valid()) { 384 return _message.get().c_str(); 385 } else { 386 return 0; 387 } 388 } 389 390 /// \brief Returns the filename. 391 /// 392 /// Returns \c 0 if the filename was not specified. 393 const char* file() const { 394 if (_file.valid()) { 395 return _file.get().c_str(); 396 } else { 397 return 0; 398 } 399 } 400 401 ///\e 402 virtual const char* what() const throw() { 403 try { 404 std::ostringstream ostr; 405 if (message()) ostr << message(); 406 if (file()) ostr << "(when reading file '" << file() << "')"; 407 _message_holder.set(ostr.str()); 408 } 409 catch (...) {} 410 if( _message_holder.valid() ) return _message_holder.get().c_str(); 411 return "lemon:IoParameterError"; 412 } 413 virtual ~IoParameterError() throw() {} 414 }; 415 416 417 ///\e 418 class AssertionFailedError : public LogicError { 419 protected: 420 const char *assertion; 421 const char *file; 422 int line; 423 const char *function; 424 const char *message; 425 426 mutable ExceptionMember<std::string> _message_holder; 427 public: 428 ///\e 429 AssertionFailedError(const char *_file, int _line, const char *func, 430 const char *msg, const char *_assertion = 0) : 431 assertion(_assertion), file(_file), line(_line), function(func), 432 message(msg) {} 433 434 ///\e 435 const char* get_assertion() const { return assertion; } 436 ///\e 437 const char* get_message() const { return message; } 438 ///\e 439 const char* get_file() const { return file; } 440 ///\e 441 const char* get_function() const { return function; } 442 ///\e 443 int get_line() const { return line; } 444 445 446 virtual const char* what() const throw() { 447 try { 448 std::ostringstream ostr; 449 ostr << file << ":" << line << ": "; 450 if( function ) 451 ostr << function << ": "; 452 ostr << message; 453 if( assertion ) 454 ostr << " (assertion '" << assertion << "' failed)"; 64 ostr << _file << ":" << _line << ": "; 65 if (_function) 66 ostr << _function << ": "; 67 ostr << _message; 68 if (_assertion) 69 ostr << " (assertion '" << _assertion << "' failed)"; 455 70 _message_holder.set(ostr.str()); 456 71 return ostr.str().c_str(); … … 460 75 return "lemon::AssertionFailedError"; 461 76 } 462 virtual ~AssertionFailedError() throw() {}77 virtual ~AssertionFailedError() throw() {} 463 78 }; 464 79 465 80 466 /**************** Macros ****************/ 467 81 inline void assert_fail_log(const char *file, int line, 82 const char *function, 83 const std::exception& exception, 84 const char *assertion) 85 { 86 std::cerr << file << ":" << line << ": "; 87 if (function) 88 std::cerr << function << ": "; 89 std::cerr << exception.what(); 90 if (assertion) 91 std::cerr << " (assertion '" << assertion << "' failed)"; 92 std::cerr << std::endl; 93 } 94 95 inline void assert_fail_log(const char *file, int line, const char *function, 96 const char *message, const char *assertion) 97 { 98 std::cerr << file << ":" << line << ": "; 99 if (function) 100 std::cerr << function << ": "; 101 std::cerr << message; 102 if (assertion) 103 std::cerr << " (assertion '" << assertion << "' failed)"; 104 std::cerr << std::endl; 105 } 106 107 inline void assert_fail_log(const char *file, int line, const char *function, 108 const std::string& message, const char *assertion) 109 { 110 assert_fail_log(file, line, function, message.c_str(), assertion); 111 } 112 113 inline void assert_fail_abort(const char *file, int line, 114 const char *function, 115 const std::exception& exception, 116 const char *assertion) 117 { 118 std::cerr << file << ":" << line << ": "; 119 if (function) 120 std::cerr << function << ": "; 121 std::cerr << exception.what(); 122 if (assertion) 123 std::cerr << " (assertion '" << assertion << "' failed)"; 124 std::cerr << std::endl; 125 std::abort(); 126 } 127 128 inline void assert_fail_abort(const char *file, int line, 129 const char *function, const char* message, 130 const char *assertion) 131 { 132 std::cerr << file << ":" << line << ": "; 133 if (function) 134 std::cerr << function << ": "; 135 std::cerr << message; 136 if (assertion) 137 std::cerr << " (assertion '" << assertion << "' failed)"; 138 std::cerr << std::endl; 139 std::abort(); 140 } 141 142 inline void assert_fail_abort(const char *file, int line, 143 const char *function, 144 const std::string& message, 145 const char *assertion) 146 { 147 assert_fail_abort(file, line, function, message.c_str(), assertion); 148 } 149 150 inline void assert_fail_error(const char *file, int line, 151 const char *function, 152 const std::exception& exception, 153 const char *assertion) 154 { 155 throw AssertionFailedError(file, line, function, 156 exception.what(), assertion); 157 } 158 159 inline void assert_fail_error(const char *file, int line, 160 const char *function, const char *message, 161 const char *assertion) 162 { 163 throw AssertionFailedError(file, line, function, message, assertion); 164 } 165 166 inline void assert_fail_error(const char *file, int line, 167 const char *function, 168 const std::string& message, 169 const char *assertion) 170 { 171 assert_fail_error(file, line, function, message.c_str(), assertion); 172 } 468 173 469 174 template <typename Exception> 470 inline void assert_fail(const char *file, int line, 471 const char *func, 472 Exception exception, 473 const char *assertion = 0, 474 bool do_abort=true) 475 { 476 using namespace std; 477 cerr << file << ":" << line << ": "; 478 if (func) 479 cerr << func << ": "; 480 cerr << exception.what(); 481 if (assertion) 482 cerr << " (assertion '" << assertion << "' failed)"; 483 cerr << endl; 484 if (do_abort) 485 abort(); 486 } 487 488 template <> 489 inline void assert_fail<const char *>(const char *file, int line, 490 const char *func, 491 const char *message, 492 const char *assertion, 493 bool do_abort) 494 { 495 using namespace std; 496 cerr << file << ":" << line << ": "; 497 if (func) 498 cerr << func << ": "; 499 cerr << message; 500 if (assertion) 501 cerr << " (assertion '" << assertion << "' failed)"; 502 cerr << endl; 503 if (do_abort) 504 abort(); 505 } 506 507 template <> 508 inline void assert_fail<std::string>(const char *file, int line, 509 const char *func, 510 std::string message, 511 const char *assertion, 512 bool do_abort) 513 { 514 assert_fail(file, line, func, message.c_str(), assertion, do_abort); 515 } 516 517 template <typename Exception> 518 inline void assert_fail_failure(const char *file, int line, const char *func, 519 Exception exception, 520 const char *assertion = 0, 521 bool = true) 522 { 523 throw AssertionFailedError(file, line, func, exception.what(), assertion); 524 } 525 526 template <> 527 inline void assert_fail_failure<const char *>(const char *file, int line, 528 const char *func, 529 const char *message, 530 const char *assertion, 531 bool) 532 { 533 throw AssertionFailedError(file, line, func, message, assertion); 534 } 535 536 template <> 537 inline void assert_fail_failure<std::string>(const char *file, int line, 538 const char *func, 539 std::string message, 540 const char *assertion, 541 bool) 542 { 543 assert_fail_failure(file, line, func, message.c_str(), assertion, true); 544 } 545 546 template <typename Exception> 547 inline void assert_fail_exception(const char *file, int line, const char *func, 548 Exception exception, 549 const char *assertion = 0, bool = true) 175 inline void assert_fail_exception(const char *, int, const char *, 176 const Exception& exception, 177 const char *, const std::exception* = 178 static_cast<const Exception*>(0)) 550 179 { 551 180 throw exception; 552 181 } 553 182 554 template <> 555 inline void assert_fail_exception<const char *>(const char *file, int line, 556 const char *func, 557 const char *message, 558 const char *assertion, 559 bool) 560 { 561 throw AssertionFailedError(file, line, func, message, assertion); 562 } 563 564 template <> 565 inline void assert_fail_exception<std::string>(const char *file, int line, 566 const char *func, 567 std::string message, 568 const char *assertion, 569 bool) 570 { 571 assert_fail_exception(file, line, func, message.c_str(), assertion, true); 183 inline void assert_fail_exception(const char *file, int line, 184 const char *function, const char *message, 185 const char *assertion) 186 { 187 throw AssertionFailedError(file, line, function, message, assertion); 188 } 189 190 inline void assert_fail_exception(const char *file, int line, 191 const char *function, 192 const std::string& message, 193 const char *assertion) 194 { 195 assert_fail_exception(file, line, function, message.c_str(), assertion); 572 196 } 573 197 … … 575 199 576 200 } 577 #endif // LEMON_ ERROR_H201 #endif // LEMON_ASSERT_H 578 202 579 203 #undef LEMON_ASSERT 580 204 #undef LEMON_FIXME 581 205 582 #ifdef LEMON_ENABLE_ASSERTS 583 # define LEMON_ASSERT_ABORT 584 #endif 585 586 #ifndef LEMON_ASSERT_DO_ABORT 587 # define LEMON_ASSERT_DO_ABORT 1 588 #endif 589 590 #ifndef LEMON_ASSERT_HANDLER 591 # if defined LEMON_ASSERT_EXCEPTION 592 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception 593 # elif defined LEMON_ASSERT_FAILURE 594 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure 595 # elif defined LEMON_ASSERT_ABORT 596 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail 597 # else 598 # define LEMON_DISABLE_ASSERTS 206 #if (defined(LEMON_ASSERT_LOG) ? 1 : 0) + \ 207 (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ 208 (defined(LEMON_ASSERT_ERROR) ? 1 : 0) + \ 209 (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) + \ 210 (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) > 1 211 #error "Lemon assertion system is not set properly" 212 #endif 213 214 #if ((defined(LEMON_ASSERT_LOG) ? 1 : 0) + \ 215 (defined(LEMON_ASSERT_ABORT) ? 1 : 0) + \ 216 (defined(LEMON_ASSERT_ERROR) ? 1 : 0) + \ 217 (defined(LEMON_ASSERT_EXCEPTION) ? 1 : 0) + \ 218 (defined(LEMON_ASSERT_CUSTOM) ? 1 : 0) == 1 || \ 219 defined(LEMON_ENABLE_ASSERT)) && \ 220 defined(LEMON_DISABLE_ASSERTS) 221 #error "Lemon assertion system is not set properly" 222 #endif 223 224 225 #if defined LEMON_ASSERT_LOG 226 # undef LEMON_ASSERT_HANDLER 227 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_log 228 #elif defined LEMON_ASSERT_ABORT 229 # undef LEMON_ASSERT_HANDLER 230 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort 231 #elif defined LEMON_ASSERT_ERROR 232 # undef LEMON_ASSERT_HANDLER 233 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_error 234 #elif defined LEMON_ASSERT_EXCEPTION 235 # undef LEMON_ASSERT_HANDLER 236 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception 237 #elif defined LEMON_ASSERT_CUSTOM 238 # undef LEMON_ASSERT_HANDLER 239 # ifndef LEMON_CUSTOM_ASSERT_HANDLER 240 # error "LEMON_CUSTOM_ASSERT_HANDLER is not set" 599 241 # endif 242 # define LEMON_ASSERT_HANDLER LEMON_CUSTOM_ASSERT_HANDLER 243 #elif defined LEMON_ENABLE_ASSERTS 244 # undef LEMON_ASSERT_HANDLER 245 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_abort 246 #else 247 # undef LEMON_ASSERT_HANDLER 248 #endif 249 250 251 #ifndef LEMON_FUNCTION_NAME 252 # define LEMON_FUNCTION_NAME (__PRETTY_FUNCTION__) 600 253 #endif 601 254 602 255 #ifdef DOXYGEN 603 256 257 /// \ingroup exceptions 258 /// 604 259 /// \brief Macro for assertions with customizable message 605 260 /// 606 /// Macro for assertions with customizable message. 261 /// Macro for assertions with customizable message. 262 /// \param exp An expression convertible to bool. If the expression is 263 /// false, then an assertion is raised. The concrete behaviour depends 264 /// on the settings of the assertion system. 265 /// \param msg A \e const \e char*, a \e const std::string& or a \e 266 /// const \e std::exception& parameter. The variable can be used to 267 /// provide information about the circumstances of failed assertion. 607 268 /// 608 269 /// The assertions are disabled in the default behaviour. You can 609 /// enable the assertions with the 270 /// enable the assertions with the following code: 610 271 /// \code 611 272 /// #define LEMON_ENABLE_ASSERTS 612 273 /// \endcode 613 /// Then an assert 614 /// provides a log on the standard error about the assertion and aborts 615 /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the 616 /// program keeps on running). 617 /// By defining LEMON_ASSERT_FAILURE or 618 /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the 619 /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT 620 /// will always throw an \c AssertionFailedError exception with 621 /// the \c msg error message. By using 622 /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown. 623 /// 624 /// The LEMON_ASSERT macro should be called with the \c exp parameter 625 /// which should be an expression convertible to bool. If the given 626 /// parameter is false the assertion is raised and one of the assertion 627 /// behaviour will be activated. The \c msg should be either a const 628 /// char* message or an exception. When the \c msg is an exception the 629 /// \ref lemon::Exception::what() "what()" function is called to retrieve and 630 /// display the error message. 631 /// 632 /// \todo We should provide some way to reset to the default behaviour, 633 /// shouldn't we? 634 /// 635 /// \todo This whole 'assert' business should be placed in a separate 636 /// include file. The boost assert is not guarded by header sentries 637 /// which may help to change the behaviour of the assertions in 638 /// the files. 639 /// 640 /// \todo __PRETTY_FUNCTION__ should be replaced by something 641 /// compiler-independent, like BOOST_CURRENT_FUNCTION 642 643 # define LEMON_ASSERT(exp, msg) \ 644 (static_cast<void> (!!(exp) ? 0 : ( \ 645 LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ 646 __PRETTY_FUNCTION__, \ 647 msg, #exp, LEMON_ASSERT_DO_ABORT), 0))) 274 /// or with compilation parameters: 275 /// \code 276 /// g++ -DLEMON_ENABLE_ASSERTS 277 /// make CXXFLAGS='-DLEMON_ENABLE_ASSERTS' 278 /// \endcode 279 /// 280 /// The %lemon assertion system has a wide range of customization 281 /// properties. As default behaviour the failed assertion prints a 282 /// short log message to the standard ouput and aborts the execution. 283 /// 284 /// The following modes can be used in the assertion system: 285 /// 286 /// - \e LEMON_ASSERT_LOG The failed assert print a short convenient 287 /// error message to the standard error and continues the 288 /// execution. 289 /// - \e LEMON_ASSERT_ABORT This mode is similar to the \e 290 /// LEMON_ASSERT_LOG, but it aborts the program. It is the default 291 /// operation mode when the asserts are enabled with \e 292 /// LEMON_ENABLE_ASSERTS. 293 /// - \e LEMON_ASSERT_ERROR The assert throws an \ref 294 /// lemon::AssertionFailedError "AssertionFailedError". If the \c 295 /// msg parameter is an exception, then the result of the \ref 296 /// lemon::Exception::what() "what()" member function is passed as 297 /// error message. 298 /// - \e LEMON_ASSERT_EXCEPTION If the specified \c msg is an 299 /// exception then it raised directly (solving that the exception 300 /// can not be thrown polymorphically), otherwise an \ref 301 /// lemon::AssertionFailedError "AssertionFailedError" is thrown with 302 /// the given parameter. 303 /// - \e LEMON_ASSERT_CUSTOM The user can define an own assertion 304 /// handler functions. Three overloaded functions should be defined 305 /// with the following parameter lists: 306 /// \code 307 /// void custom_assert_handler(const char* file, int line, 308 /// const char* function, const char* message, const char* expression); 309 /// void custom_assert_handler(const char* file, int line, 310 /// const char* function, const std::string& message, const char* expression); 311 /// void custom_assert_handler(const char* file, int line, 312 /// const char* function, const std::exception& message, const char* expression); 313 /// \endcode 314 /// The name of the functions should be defined as the \c 315 /// LEMON_CUSTOM_ASSERT_HANDLER macro name. 316 /// \code 317 /// #define LEMON_CUSTOM_ASSERT_HANDLER custom_assert_handler 318 /// \endcode 319 /// Whenever an assertion is occured, one of the custom assertion 320 /// handler is called with appropiate parameters. 321 /// 322 /// The assertion mode can be changed within one compilation unit, if 323 /// the macros are redefined with other settings and the 324 /// lemon/assert.h file is reincluded then the behaviour is changed 325 /// appropiately to the new settings. 326 # define LEMON_ASSERT(exp, msg) \ 327 (static_cast<void> (!!(exp) ? 0 : ( \ 328 LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ 329 LEMON_FUNCTION_NAME, \ 330 msg, #exp), 0))) 331 332 333 /// \ingroup exceptions 334 /// 335 /// \brief Macro for mark not yet implemented features. 336 /// 337 /// Macro for mark not yet implemented features and outstanding bugs. 338 /// It is close to be the shortcut of the following code: 339 /// \code 340 /// LEMON_ASSERT(false, msg); 341 /// \endcode 342 # define LEMON_FIXME(msg) \ 343 (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME, \ 344 "FIXME: " msg, static_cast<const char*>(0))) 648 345 649 346 #else 650 # if defined LEMON_DISABLE_ASSERTS 651 347 348 # ifndef LEMON_ASSERT_HANDLER 652 349 # define LEMON_ASSERT(exp, msg) (static_cast<void> (0)) 653 350 # define LEMON_FIXME(msg) (static_cast<void>(0)) 654 351 # else 655 352 # define LEMON_ASSERT(exp, msg) \ 656 353 (static_cast<void> (!!(exp) ? 0 : ( \ 657 354 LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \ 658 __PRETTY_FUNCTION__, \ 659 msg, #exp, LEMON_ASSERT_DO_ABORT), 0))) 355 LEMON_FUNCTION_NAME, \ 356 msg, #exp), 0))) 357 # define LEMON_FIXME(msg) \ 358 (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, LEMON_FUNCTION_NAME, \ 359 "FIXME: " msg, static_cast<const char*>(0))) 660 360 # endif 661 #endif 662 663 /** 664 * \brief Macro for mark not yet implemented features. 665 * 666 * \todo Is this the right place for this? It should be used only in 667 * modules under development. 668 * 669 * \todo __PRETTY_FUNCTION__ should be replaced by something 670 * compiler-independent, like BOOST_CURRENT_FUNCTION 671 */ 672 673 #define LEMON_FIXME(msg) \ 674 (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \ 675 "FIXME: " msg)) 361 362 #endif 363 364 -
lemon/error.h
r66 r108 94 94 }; 95 95 96 /// Exception-safe convenient "error message"class.96 /// Exception-safe convenient error message builder class. 97 97 98 98 /// Helper class which provides a convenient ostream-like (operator << … … 414 414 }; 415 415 416 417 ///\e 418 class AssertionFailedError : public LogicError { 419 protected: 420 const char *assertion; 421 const char *file; 422 int line; 423 const char *function; 424 const char *message; 425 426 mutable ExceptionMember<std::string> _message_holder; 427 public: 428 ///\e 429 AssertionFailedError(const char *_file, int _line, const char *func, 430 const char *msg, const char *_assertion = 0) : 431 assertion(_assertion), file(_file), line(_line), function(func), 432 message(msg) {} 433 434 ///\e 435 const char* get_assertion() const { return assertion; } 436 ///\e 437 const char* get_message() const { return message; } 438 ///\e 439 const char* get_file() const { return file; } 440 ///\e 441 const char* get_function() const { return function; } 442 ///\e 443 int get_line() const { return line; } 444 445 446 virtual const char* what() const throw() { 447 try { 448 std::ostringstream ostr; 449 ostr << file << ":" << line << ": "; 450 if( function ) 451 ostr << function << ": "; 452 ostr << message; 453 if( assertion ) 454 ostr << " (assertion '" << assertion << "' failed)"; 455 _message_holder.set(ostr.str()); 456 return ostr.str().c_str(); 457 } 458 catch(...) {} 459 if( _message_holder.valid() ) return _message_holder.get().c_str(); 460 return "lemon::AssertionFailedError"; 461 } 462 virtual ~AssertionFailedError() throw() {} 463 }; 464 465 466 /**************** Macros ****************/ 467 468 469 template <typename Exception> 470 inline void assert_fail(const char *file, int line, 471 const char *func, 472 Exception exception, 473 const char *assertion = 0, 474 bool do_abort=true) 475 { 476 using namespace std; 477 cerr << file << ":" << line << ": "; 478 if (func) 479 cerr << func << ": "; 480 cerr << exception.what(); 481 if (assertion) 482 cerr << " (assertion '" << assertion << "' failed)"; 483 cerr << endl; 484 if (do_abort) 485 abort(); 486 } 487 488 template <> 489 inline void assert_fail<const char *>(const char *file, int line, 490 const char *func, 491 const char *message, 492 const char *assertion, 493 bool do_abort) 494 { 495 using namespace std; 496 cerr << file << ":" << line << ": "; 497 if (func) 498 cerr << func << ": "; 499 cerr << message; 500 if (assertion) 501 cerr << " (assertion '" << assertion << "' failed)"; 502 cerr << endl; 503 if (do_abort) 504 abort(); 505 } 506 507 template <> 508 inline void assert_fail<std::string>(const char *file, int line, 509 const char *func, 510 std::string message, 511 const char *assertion, 512 bool do_abort) 513 { 514 assert_fail(file, line, func, message.c_str(), assertion, do_abort); 515 } 516 517 template <typename Exception> 518 inline void assert_fail_failure(const char *file, int line, const char *func, 519 Exception exception, 520 const char *assertion = 0, 521 bool = true) 522 { 523 throw AssertionFailedError(file, line, func, exception.what(), assertion); 524 } 525 526 template <> 527 inline void assert_fail_failure<const char *>(const char *file, int line, 528 const char *func, 529 const char *message, 530 const char *assertion, 531 bool) 532 { 533 throw AssertionFailedError(file, line, func, message, assertion); 534 } 535 536 template <> 537 inline void assert_fail_failure<std::string>(const char *file, int line, 538 const char *func, 539 std::string message, 540 const char *assertion, 541 bool) 542 { 543 assert_fail_failure(file, line, func, message.c_str(), assertion, true); 544 } 545 546 template <typename Exception> 547 inline void assert_fail_exception(const char *file, int line, const char *func, 548 Exception exception, 549 const char *assertion = 0, bool = true) 550 { 551 throw exception; 552 } 553 554 template <> 555 inline void assert_fail_exception<const char *>(const char *file, int line, 556 const char *func, 557 const char *message, 558 const char *assertion, 559 bool) 560 { 561 throw AssertionFailedError(file, line, func, message, assertion); 562 } 563 564 template <> 565 inline void assert_fail_exception<std::string>(const char *file, int line, 566 const char *func, 567 std::string message, 568 const char *assertion, 569 bool) 570 { 571 assert_fail_exception(file, line, func, message.c_str(), assertion, true); 572 } 573 574 /// @} 416 /// @} 575 417 576 418 } 419 577 420 #endif // LEMON_ERROR_H 578 579 #undef LEMON_ASSERT580 #undef LEMON_FIXME581 582 #ifdef LEMON_ENABLE_ASSERTS583 # define LEMON_ASSERT_ABORT584 #endif585 586 #ifndef LEMON_ASSERT_DO_ABORT587 # define LEMON_ASSERT_DO_ABORT 1588 #endif589 590 #ifndef LEMON_ASSERT_HANDLER591 # if defined LEMON_ASSERT_EXCEPTION592 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_exception593 # elif defined LEMON_ASSERT_FAILURE594 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail_failure595 # elif defined LEMON_ASSERT_ABORT596 # define LEMON_ASSERT_HANDLER ::lemon::assert_fail597 # else598 # define LEMON_DISABLE_ASSERTS599 # endif600 #endif601 602 #ifdef DOXYGEN603 604 /// \brief Macro for assertions with customizable message605 ///606 /// Macro for assertions with customizable message.607 ///608 /// The assertions are disabled in the default behaviour. You can609 /// enable the assertions with the610 /// \code611 /// #define LEMON_ENABLE_ASSERTS612 /// \endcode613 /// Then an assert614 /// provides a log on the standard error about the assertion and aborts615 /// the program if LEMON_ASSERT_DO_ABORT is also defined (otherwise the616 /// program keeps on running).617 /// By defining LEMON_ASSERT_FAILURE or618 /// LEMON_ASSERT_EXCEPTION, you can set other behaviour to the619 /// assertions. In case LEMON_ASSERT_FAILURE is given, LEMON_ASSERT620 /// will always throw an \c AssertionFailedError exception with621 /// the \c msg error message. By using622 /// LEMON_ASSERT_EXCEPTION, one can define an arbitrary exception to be thrown.623 ///624 /// The LEMON_ASSERT macro should be called with the \c exp parameter625 /// which should be an expression convertible to bool. If the given626 /// parameter is false the assertion is raised and one of the assertion627 /// behaviour will be activated. The \c msg should be either a const628 /// char* message or an exception. When the \c msg is an exception the629 /// \ref lemon::Exception::what() "what()" function is called to retrieve and630 /// display the error message.631 ///632 /// \todo We should provide some way to reset to the default behaviour,633 /// shouldn't we?634 ///635 /// \todo This whole 'assert' business should be placed in a separate636 /// include file. The boost assert is not guarded by header sentries637 /// which may help to change the behaviour of the assertions in638 /// the files.639 ///640 /// \todo __PRETTY_FUNCTION__ should be replaced by something641 /// compiler-independent, like BOOST_CURRENT_FUNCTION642 643 # define LEMON_ASSERT(exp, msg) \644 (static_cast<void> (!!(exp) ? 0 : ( \645 LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \646 __PRETTY_FUNCTION__, \647 msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))648 649 #else650 # if defined LEMON_DISABLE_ASSERTS651 652 # define LEMON_ASSERT(exp, msg) (static_cast<void> (0))653 654 # else655 # define LEMON_ASSERT(exp, msg) \656 (static_cast<void> (!!(exp) ? 0 : ( \657 LEMON_ASSERT_HANDLER(__FILE__, __LINE__, \658 __PRETTY_FUNCTION__, \659 msg, #exp, LEMON_ASSERT_DO_ABORT), 0)))660 # endif661 #endif662 663 /**664 * \brief Macro for mark not yet implemented features.665 *666 * \todo Is this the right place for this? It should be used only in667 * modules under development.668 *669 * \todo __PRETTY_FUNCTION__ should be replaced by something670 * compiler-independent, like BOOST_CURRENT_FUNCTION671 */672 673 #define LEMON_FIXME(msg) \674 (LEMON_ASSERT_HANDLER(__FILE__, __LINE__, __PRETTY_FUNCTION__, \675 "FIXME: " msg)) -
test/Makefile.am
r106 r108 13 13 test/digraph_test \ 14 14 test/dim_test \ 15 test/error_test \ 15 16 test/graph_test \ 16 17 test/kruskal_test \ … … 29 30 test_digraph_test_SOURCES = test/digraph_test.cc 30 31 test_dim_test_SOURCES = test/dim_test.cc 31 #test_error_test_SOURCES = test/error_test.cc32 test_error_test_SOURCES = test/error_test.cc 32 33 test_graph_test_SOURCES = test/graph_test.cc 33 34 # test_heap_test_SOURCES = test/heap_test.cc -
test/error_test.cc
r66 r108 23 23 24 24 using namespace lemon; 25 using std::cout; 26 using std::endl; 27 28 void faulty_fn() { 29 fault("This is a fault message"); 30 } 31 32 void exception_fn() { 33 throw Exception("This is a function throwing exception with some args: ") 34 << 5 << ", " << 18; 35 } 36 37 void unfinished_fn() { 38 LEMON_FIXME("unfinished_fn() is unfinished!"); 39 } 25 26 #ifdef LEMON_ENABLE_ASSERTS 27 #undef LEMON_ENABLE_ASSERTS 28 #endif 29 30 #ifdef LEMON_DISABLE_ASSERTS 31 #undef LEMON_DISABLE_ASSERTS 32 #endif 33 34 //checking disabled asserts 35 #define LEMON_DISABLE_ASSERTS 36 #include <lemon/assert.h> 37 38 void no_assertion_text_disable() { 39 LEMON_ASSERT(true, "This is a fault message"); 40 } 41 42 void no_assertion_exception_disable() { 43 LEMON_ASSERT(true, Exception()); 44 } 45 46 void assertion_text_disable() { 47 LEMON_ASSERT(false, "This is a fault message"); 48 } 49 50 void assertion_exception_disable() { 51 LEMON_ASSERT(false, Exception()); 52 } 53 54 void fixme_disable() { 55 LEMON_FIXME("fixme_disable() is fixme!"); 56 } 57 58 void check_assertion_disable() { 59 no_assertion_text_disable(); 60 no_assertion_exception_disable(); 61 assertion_exception_disable(); 62 assertion_text_disable(); 63 fixme_disable(); 64 } 65 #undef LEMON_DISABLE_ASSERTS 66 67 68 #define LEMON_ASSERT_ERROR 69 #include <lemon/assert.h> 70 71 void no_assertion_text_error() { 72 LEMON_ASSERT(true, "This is a fault message"); 73 } 74 75 void no_assertion_exception_error() { 76 LEMON_ASSERT(true, Exception()); 77 } 78 79 void assertion_text_error() { 80 LEMON_ASSERT(false, "This is a fault message"); 81 } 82 83 void assertion_exception_error() { 84 LEMON_ASSERT(false, Exception()); 85 } 86 87 void fixme_error() { 88 LEMON_FIXME("fixme_error() is fixme!"); 89 } 90 91 void check_assertion_error() { 92 no_assertion_text_error(); 93 no_assertion_exception_error(); 94 try { 95 assertion_exception_error(); 96 check(false, "Assertion error"); 97 } catch (const AssertionFailedError& e) { 98 } 99 100 try { 101 assertion_text_error(); 102 check(false, "Assertion error"); 103 } catch (const AssertionFailedError& e) { 104 } 105 106 try { 107 fixme_error(); 108 check(false, "Assertion error"); 109 } catch (const AssertionFailedError& e) { 110 } 111 } 112 #undef LEMON_ASSERT_ERROR 113 114 #define LEMON_ASSERT_EXCEPTION 115 #include <lemon/assert.h> 116 117 void no_assertion_text_exception() { 118 LEMON_ASSERT(true, "This is a fault message"); 119 } 120 121 void no_assertion_exception_exception() { 122 LEMON_ASSERT(true, Exception()); 123 } 124 125 void assertion_text_exception() { 126 LEMON_ASSERT(false, "This is a fault message"); 127 } 128 129 void assertion_exception_exception() { 130 LEMON_ASSERT(false, Exception()); 131 } 132 133 void fixme_exception() { 134 LEMON_FIXME("fixme_exception() is fixme!"); 135 } 136 137 void check_assertion_exception() { 138 no_assertion_text_exception(); 139 no_assertion_exception_exception(); 140 try { 141 assertion_exception_exception(); 142 check(false, "Assertion error"); 143 } catch (const Exception& e) { 144 } 145 146 try { 147 assertion_text_exception(); 148 check(false, "Assertion error"); 149 } catch (const AssertionFailedError& e) { 150 } 151 152 try { 153 assertion_text_exception(); 154 check(false, "Assertion error"); 155 } catch (const AssertionFailedError& e) { 156 } 157 158 try { 159 fixme_exception(); 160 check(false, "Assertion error"); 161 } catch (const AssertionFailedError& e) { 162 } 163 } 164 #undef LEMON_ASSERT_EXCEPTION 165 166 #define LEMON_ASSERT_LOG 167 168 #include <lemon/assert.h> 169 170 void no_assertion_text_log() { 171 LEMON_ASSERT(true, "This is a fault message"); 172 } 173 174 void no_assertion_exception_log() { 175 LEMON_ASSERT(true, Exception()); 176 } 177 178 void assertion_text_log() { 179 LEMON_ASSERT(false, "This is a fault message"); 180 } 181 182 void assertion_exception_log() { 183 LEMON_ASSERT(false, Exception()); 184 } 185 186 void fixme_log() { 187 LEMON_FIXME("fixme_log() is fixme!"); 188 } 189 190 void check_assertion_log() { 191 no_assertion_text_log(); 192 no_assertion_exception_log(); 193 std::cerr << "The next 3 failure messages are expected: " << std::endl; 194 assertion_exception_log(); 195 assertion_text_log(); 196 fixme_log(); 197 std::cerr << "End of expected error messages" << std::endl; 198 } 199 #undef LEMON_ASSERT_LOG 200 201 #define LEMON_ASSERT_CUSTOM 202 203 static int cnt = 0; 204 void my_assert_handler(const char*, int, const char*, 205 const char*, const char*) { 206 ++cnt; 207 } 208 209 void my_assert_handler(const char*, int, const char*, 210 const std::exception&, const char*) { 211 ++cnt; 212 } 213 214 void my_assert_handler(const char*, int, const char*, 215 const std::string&, const char*) { 216 ++cnt; 217 } 218 219 220 #define LEMON_CUSTOM_ASSERT_HANDLER my_assert_handler 221 #include <lemon/assert.h> 222 223 void no_assertion_text_custom() { 224 LEMON_ASSERT(true, "This is a fault message"); 225 } 226 227 void no_assertion_exception_custom() { 228 LEMON_ASSERT(true, Exception()); 229 } 230 231 void assertion_text_custom() { 232 LEMON_ASSERT(false, "This is a fault message"); 233 } 234 235 void assertion_exception_custom() { 236 LEMON_ASSERT(false, Exception()); 237 } 238 239 void fixme_custom() { 240 LEMON_FIXME("fixme_custom() is fixme!"); 241 } 242 243 void check_assertion_custom() { 244 no_assertion_text_custom(); 245 no_assertion_exception_custom(); 246 assertion_exception_custom(); 247 assertion_text_custom(); 248 fixme_custom(); 249 check(cnt == 3, "The custom assert handler does not work"); 250 } 251 252 #undef LEMON_ASSERT_CUSTOM 40 253 41 254 42 255 int main() { 43 try { 44 faulty_fn(); 45 check(false, "A faulty function did not fail."); 46 } 47 catch(const Exception &e) { 48 cout << "Exeption = \"" << e.what() << "\" (Right behaviour)" << endl; 49 } 50 51 try { 52 exception_fn(); 53 check(false, "The function did not throw Exception."); 54 } 55 catch(const Exception &e) { 56 cout << "Exeption = \"" << e.what() << "\" (Right behaviour)" << endl; 57 } 58 59 try { 60 unfinished_fn(); 61 check(false, "FIXME macro does not work."); 62 } 63 catch(const Exception &e) { 64 cout << "Exeption = \"" << e.what() << "\" (Right behaviour)" << endl; 65 } 256 check_assertion_disable(); 257 check_assertion_error(); 258 check_assertion_exception(); 259 check_assertion_log(); 260 check_assertion_custom(); 66 261 67 262 return 0;
Note: See TracChangeset
for help on using the changeset viewer.