Scythe-1.0.3
|
00001 /* 00002 * Scythe Statistical Library Copyright (C) 2000-2002 Andrew D. Martin 00003 * and Kevin M. Quinn; 2002-present Andrew D. Martin, Kevin M. Quinn, 00004 * and Daniel Pemstein. All Rights Reserved. 00005 * 00006 * This program is free software; you can redistribute it and/or 00007 * modify under the terms of the GNU General Public License as 00008 * published by Free Software Foundation; either version 2 of the 00009 * License, or (at your option) any later version. See the text files 00010 * COPYING and LICENSE, distributed with this source code, for further 00011 * information. 00012 * -------------------------------------------------------------------- 00013 * scythestat/error.h 00014 */ 00015 00051 #ifndef SCYTHE_ERROR_H 00052 #define SCYTHE_ERROR_H 00053 00054 #include <exception> 00055 #include <string> 00056 #include <sstream> 00057 #include <iostream> 00058 #include <vector> 00059 #include <cstring> 00060 00061 #ifdef SCYTHE_RPACK 00062 #include <R.h> // needed to use Rprintf() 00063 #include <R_ext/Utils.h> // needed to allow user interrupts 00064 #endif 00065 00067 #ifdef SCYTHE_DEBUG_LIB 00068 #define SCYTHE_DEBUG_MSG(MSG) \ 00069 { std::cout << "SCYTHE_DEBUG_LIB: " << MSG << std::endl; } 00070 #else 00071 #define SCYTHE_DEBUG_MSG(MSG) 00072 #endif 00073 00075 #define SCYTHE_THROW(EXCEP,MSG) \ 00076 { \ 00077 std::stringstream _SCYTHE_DEBUG_ss; \ 00078 _SCYTHE_DEBUG_ss << MSG; \ 00079 throw EXCEP(__FILE__, __func__, __LINE__, \ 00080 _SCYTHE_DEBUG_ss.str()); \ 00081 } 00082 00083 #define SCYTHE_CHECK(CHECK,EXCEP,MSG) \ 00084 { \ 00085 if (CHECK) \ 00086 SCYTHE_THROW(EXCEP,MSG) \ 00087 } 00088 00089 #define SCYTHE_WARN_RPACK(MSG) \ 00090 { \ 00091 std::stringstream _SCYTHE_WARN_ss; \ 00092 _SCYTHE_WARN_ss << "WARNING in " << __FILE__ << ", " \ 00093 << __func__ << ", " << __LINE__ << ": " \ 00094 << MSG << "\n"; \ 00095 Rprintf(_SCYTHE_WARN_ss.str().c_str()); \ 00096 } 00097 00098 #define SCYTHE_WARN_STD(MSG) \ 00099 std::cerr << "WARNING in " << __FILE__ << ", " \ 00100 << __func__ << ", " << __LINE__ << ": " \ 00101 << MSG << "\n"; 00102 00103 #ifdef SCYTHE_RPACK 00104 #define SCYTHE_WARN SCYTHE_WARN_RPACK 00105 #else 00106 #define SCYTHE_WARN SCYTHE_WARN_STD 00107 #endif 00108 00109 #define SCYTHE_CHECK_WARN(CHECK,MSG) \ 00110 { \ 00111 if (CHECK) \ 00112 SCYTHE_WARN(MSG) \ 00113 } 00114 00116 #ifndef SCYTHE_DEBUG 00117 #define SCYTHE_DEBUG 3 00118 #endif 00119 00121 #if SCYTHE_DEBUG > 0 00122 #define SCYTHE_CHECK_10(CHECK,EXCEP,MSG) SCYTHE_CHECK(CHECK,EXCEP,MSG) 00123 #else 00124 #define SCYTHE_CHECK_10(CHECK, EXCEP, MSG) 00125 #endif 00126 00127 #if SCYTHE_DEBUG > 1 00128 #define SCYTHE_CHECK_20(CHECK,EXCEP,MSG) SCYTHE_CHECK(CHECK,EXCEP,MSG) 00129 #else 00130 #define SCYTHE_CHECK_20(CHECK, EXCEP, MSG) 00131 #endif 00132 00133 #if SCYTHE_DEBUG > 2 00134 #define SCYTHE_CHECK_30(CHECK,EXCEP,MSG) SCYTHE_CHECK(CHECK,EXCEP,MSG) 00135 #else 00136 #define SCYTHE_CHECK_30(CHECK, EXCEP, MSG) 00137 #endif 00138 00139 #if SCYTHE_DEBUG > 0 00140 #define SCYTHE_THROW_10(EXCEP,MSG) SCYTHE_THROW(EXCEP,MSG) 00141 #else 00142 #define SCYTHE_THROW_10(EXCEP,MSG) 00143 #endif 00144 00145 #if SCYTHE_DEBUG > 1 00146 #define SCYTHE_THROW_20(EXCEP,MSG) SCYTHE_THROW(EXCEP,MSG) 00147 #else 00148 #define SCYTHE_THROW_20(EXCEP,MSG) 00149 #endif 00150 00151 #if SCYTHE_DEBUG > 2 00152 #define SCYTHE_THROW_30(EXCEP,MSG) SCYTHE_THROW(EXCEP,MSG) 00153 #else 00154 #define SCYTHE_THROW_30(EXCEP,MSG) 00155 #endif 00156 00157 namespace scythe 00158 { 00159 /* Forward declaration for serr */ 00160 class scythe_exception; 00161 00162 /**** This file-local variable holds the output of the last 00163 * scythe_exception constructed. 00164 ****/ 00165 #ifdef __MINGW32__ 00166 static scythe_exception *serr; 00167 #else 00168 namespace 00169 { 00170 scythe_exception *serr; 00171 } 00172 #endif 00173 00174 /**** A replacement for the default terminate handler. This outputs 00175 * the string held in serr before calling abort, thereby notifying 00176 * the user of why the program crashed. 00177 ****/ 00178 inline void scythe_terminate (); 00179 00180 /**** The scythe exception abstract base class ****/ 00189 class scythe_exception:public std::exception 00190 { 00191 public: 00192 scythe_exception (const std::string & head, 00193 const std::string & file, 00194 const std::string & function, 00195 const unsigned int &line, 00196 const std::string & message = "", 00197 const bool & halt = false) throw () 00198 : exception (), 00199 head_ (head), 00200 file_ (file), 00201 function_ (function), 00202 line_ (line), 00203 message_ (message), 00204 call_files_ (), 00205 call_funcs_ (), 00206 call_lines_ () 00207 { 00208 std::ostringstream os; 00209 os << head_ << " in " << file_ << ", " << function_ << ", " 00210 << line_ << ": " << message_ << "!\n\n"; 00211 00212 serr = this; 00213 std::set_terminate (scythe_terminate); 00214 if (halt) { 00215 #ifdef SCYTHE_RPACK 00216 error("Aborting Scythe C++ execution"); 00217 #else 00218 std::terminate (); 00219 #endif 00220 } 00221 } 00222 00223 scythe_exception (const scythe_exception & e) throw () 00224 : exception (), 00225 head_ (e.head_), 00226 file_ (e.file_), 00227 function_ (e.function_), 00228 line_ (e.line_), 00229 message_ (e.message_), 00230 call_files_ (e.call_files_), 00231 call_funcs_ (e.call_funcs_), 00232 call_lines_ (e.call_lines_) 00233 { 00234 } 00235 00236 scythe_exception & operator= (const scythe_exception & e) throw () 00237 { 00238 head_ = e.head_; 00239 file_ = e.file_; 00240 function_ = e.function_; 00241 line_ = e.line_; 00242 message_ = e.message_; 00243 00244 return *this; 00245 } 00246 00247 virtual ~ scythe_exception () throw () 00248 { 00249 } 00250 00251 /* This function is only called from scythe_terminate, and only 00252 * once, so this memory leak is not an issue. We can't just return 00253 * os.str().c_str() because that is a dangling pointer after the 00254 * function returns... 00255 * TODO: Deal with memory leak issue that might affect R packages 00256 */ 00257 virtual const char *what () const throw () 00258 { 00259 std::ostringstream os; 00260 for (int i = call_files_.size() - 1; i > -1; ++i) { 00261 os << "Called from " << call_files_[i] << ", " 00262 << call_funcs_[i] << ", " << call_lines_[i] << std::endl; 00263 } 00264 os << head_ << " in " << file_ << ", " << function_ << ", " 00265 << line_ << ": " << message_ << "!"; 00266 char *retval = new char[os.str().length()]; 00267 std::strcpy(retval, os.str().c_str()); 00268 return retval; 00269 } 00270 00271 virtual std::string message () const throw () 00272 { 00273 return message_; 00274 } 00275 00276 virtual void add_caller (const std::string &file, 00277 const std::string &function, const unsigned int &line) throw () 00278 { 00279 00280 /* This if allows one to catch and rethrow an error in the same 00281 * function w/out messing things up. Nice to keep try-catch 00282 * blocks to a minimum 00283 */ 00284 00285 if (file != file_ && function != function_) { 00286 call_files_.push_back(file); 00287 call_funcs_.push_back(function); 00288 call_lines_.push_back(line); 00289 } 00290 } 00291 00292 private: 00293 std::string head_; 00294 std::string file_; 00295 std::string function_; 00296 unsigned int line_; 00297 std::string message_; 00298 std::vector<std::string> call_files_; 00299 std::vector<std::string> call_funcs_; 00300 std::vector<unsigned int> call_lines_; 00301 }; 00302 00303 00304 /**** Exception class types, added as needed ****/ 00305 00313 class scythe_alloc_error:public scythe_exception 00314 { 00315 public: 00316 scythe_alloc_error (const std::string & file, 00317 const std::string & function, 00318 const unsigned int &line, 00319 const std::string & message = "", 00320 const bool & halt = false) throw () 00321 : scythe_exception ("SCYTHE_ALLOCATION_ERROR", file, function, 00322 line, message, halt) 00323 { 00324 } 00325 }; 00326 00334 class scythe_invalid_arg:public scythe_exception 00335 { 00336 public: 00337 scythe_invalid_arg (const std::string & file, 00338 const std::string & function, 00339 const unsigned int &line, 00340 const std::string & message = "", 00341 const bool & halt = false) throw () 00342 : scythe_exception ("SCYTHE_INVALID ARGUMENT", file, function, 00343 line, message, halt) 00344 { 00345 } 00346 }; 00347 00355 class scythe_file_error:public scythe_exception 00356 { 00357 public: 00358 scythe_file_error(const std::string & file, 00359 const std::string & function, 00360 const unsigned int &line, 00361 const std::string & message = "", 00362 const bool & halt = false) throw () 00363 : scythe_exception ("SCYTHE FILE ERROR", file, function, line, 00364 message, halt) 00365 { 00366 } 00367 }; 00368 00375 class scythe_conformation_error:public scythe_exception 00376 { 00377 public: 00378 scythe_conformation_error(const std::string & file, 00379 const std::string & function, 00380 const unsigned int &line, 00381 const std::string & message = "", 00382 const bool & halt = false) throw () 00383 : scythe_exception ("SCYTHE CONFORMATION ERROR", file, function, 00384 line, message, halt) 00385 { 00386 } 00387 }; 00388 00397 class scythe_dimension_error:public scythe_exception 00398 { 00399 public: 00400 scythe_dimension_error (const std::string & file, 00401 const std::string & function, 00402 const unsigned int &line, 00403 const std::string & message = "", 00404 const bool & halt = false) throw () 00405 : scythe_exception ("SCYTHE DIMENSION ERROR", file, function, 00406 line, message, halt) 00407 { 00408 } 00409 }; 00410 00418 class scythe_null_error:public scythe_exception 00419 { 00420 public: 00421 scythe_null_error(const std::string & file, 00422 const std::string & function, 00423 const unsigned int &line, 00424 const std::string & message = "", 00425 const bool & halt = false) throw () 00426 : scythe_exception ("SCYTHE NULL ERROR", file, function, line, 00427 message, halt) 00428 { 00429 } 00430 }; 00431 00441 class scythe_type_error:public scythe_exception 00442 { 00443 public: 00444 scythe_type_error(const std::string & file, 00445 const std::string & function, 00446 const unsigned int &line, 00447 const std::string & message = "", 00448 const bool & halt = false) throw () 00449 : scythe_exception ("SCYTHE TYPE ERROR", file, function, line, 00450 message, halt) 00451 { 00452 } 00453 }; 00454 00462 class scythe_bounds_error:public scythe_exception 00463 { 00464 public: 00465 scythe_bounds_error(const std::string & file, 00466 const std::string & function, 00467 const unsigned int &line, 00468 const std::string & message = "", 00469 const bool & halt = false) throw () 00470 : scythe_exception ("SCYTHE BOUNDS ERROR", file, function, 00471 line, message, halt) 00472 { 00473 } 00474 }; 00475 00483 class scythe_convergence_error:public scythe_exception 00484 { 00485 public: 00486 scythe_convergence_error (const std::string & file, 00487 const std::string & function, 00488 const unsigned int &line, 00489 const std::string & message = "", 00490 const bool & halt = false) throw () 00491 : scythe_exception ("SCYTHE CONVERGENCE ERROR", file, function, 00492 line, message, halt) 00493 { 00494 } 00495 }; 00496 00505 class scythe_range_error:public scythe_exception 00506 { 00507 public: 00508 scythe_range_error (const std::string & file, 00509 const std::string & function, 00510 const unsigned int &line, 00511 const std::string & message = "", 00512 const bool & halt = false) throw () 00513 : scythe_exception ("SCYTHE RANGE ERROR", file, function, line, 00514 message, halt) 00515 { 00516 } 00517 }; 00518 00528 class scythe_precision_error:public scythe_exception 00529 { 00530 public: 00531 scythe_precision_error (const std::string & file, 00532 const std::string & function, 00533 const unsigned int &line, 00534 const std::string & message = "", 00535 const bool & halt = false) throw () 00536 : scythe_exception ("SCYTHE PRECISION ERROR", file, function, 00537 line, message, halt) 00538 { 00539 } 00540 }; 00541 00550 class scythe_randseed_error:public scythe_exception 00551 { 00552 public: 00553 scythe_randseed_error(const std::string & file, 00554 const std::string & function, 00555 const unsigned int &line, 00556 const std::string & message = "", 00557 const bool & halt = false) throw () 00558 : scythe_exception ("SCYTHE RANDOM SEED ERROR", file, function, 00559 line, message, halt) 00560 { 00561 } 00562 }; 00563 00573 class scythe_style_error:public scythe_exception 00574 { 00575 public: 00576 scythe_style_error(const std::string& file, 00577 const std::string& function, 00578 const unsigned int& line, 00579 const std::string& message = "", 00580 const bool& halt = false) throw () 00581 : scythe_exception("SCYTHE STYLE ERROR", file, function, 00582 line, message, halt) 00583 {} 00584 }; 00585 00592 class scythe_lapack_internal_error:public scythe_exception 00593 { 00594 public: 00595 scythe_lapack_internal_error(const std::string& file, 00596 const std::string& function, 00597 const unsigned int& line, 00598 const std::string& message = "", 00599 const bool& halt = false) throw () 00600 : scythe_exception("SCYTHE LAPACK/BLAS INTERNAL ERROR", file, 00601 function, line, message, halt) 00602 {} 00603 }; 00604 00611 class scythe_unexpected_default_error:public scythe_exception 00612 { 00613 public: 00614 scythe_unexpected_default_error(const std::string& file, 00615 const std::string& function, 00616 const unsigned int& line, 00617 const std::string& message = "", 00618 const bool& halt = false) throw () 00619 : scythe_exception("SCYTHE UNEXPECTED DEFAULT ERROR", file, 00620 function, line, message, halt) 00621 {} 00622 }; 00623 00624 // The definition of our terminate handler described above 00625 inline void scythe_terminate () 00626 { 00627 #ifdef SCYTHE_RPACK 00628 Rprintf(serr->what()); 00629 error("Aborting Scythe C++ execution"); 00630 #else 00631 std::cerr << serr->what() << std::endl; 00632 std::cerr << std::endl; 00633 abort (); 00634 #endif 00635 } 00636 00637 } // end namspace SCYTHE 00638 00639 #endif /* SCYTHE_ERROR_H */