Scythe-1.0.3
error.h
Go to the documentation of this file.
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 */