// @HEADER // *********************************************************************** // // Teuchos: Common Tools Package // Copyright (2004) Sandia Corporation // // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive // license for use of this work by or on behalf of the U.S. Government. // // This library is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation; either version 2.1 of the // License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, but // WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 // USA // Questions? Contact Michael A. Heroux (maherou@sandia.gov) // // *********************************************************************** // @HEADER #ifndef TEUCHOS_TEST_FOR_EXCEPTION_H #define TEUCHOS_TEST_FOR_EXCEPTION_H /*! \file Teuchos_TestForException.hpp \brief Macro for throwing an exception with breakpointing to ease debugging. */ #include "Teuchos_TypeNameTraits.hpp" /*! \defgroup TestForException_grp Utility code for throwing exceptions and setting breakpoints. \ingroup teuchos_language_support_grp */ //@{ /** \brief Increment the throw number. */ void TestForException_incrThrowNumber(); /** \brief Increment the throw number. */ int TestForException_getThrowNumber(); /** \brief The only purpose for this function is to set a breakpoint. */ void TestForException_break( const std::string &msg ); /** \brief Macro for throwing an exception with breakpointing to ease debugging * * @param throw_exception_test * [in] Test for when to throw the exception. This can and * should be an expression that may mean something to the user. * The text verbatim of this expression is included in the * formed error string. * @param Exception * [in] This should be the name of an exception class. The * only requirement for this class is that it have a constructor * that accepts an std::string object (as all of the standard * exception classes do). * @param msg [in] This is any expression that can be included in an * output stream operation. This is useful when buinding * error messages on the fly. Note that the code in this * argument only gets evaluated if throw_exception_test * evaluates to true when an exception is throw. * * The way that this macro is intended to be used is to * call it in the source code like a function. For example, * suppose that in a piece of code in the file my_source_file.cpp * that the exception std::out_of_range is thrown if n > 100. * To use the macro, the source code would contain (at line 225 * for instance): \verbatim TEST_FOR_EXCEPTION( n > 100, std::out_of_range , "Error, n = " << n << is bad" ); \endverbatim * When the program runs and with n = 125 > 100 for instance, * the std::out_of_range exception would be thrown with the * error message: \verbatim /home/bob/project/src/my_source_file.cpp:225: n > 100: Error, n = 125 is bad \endverbatim * * In order to debug this, simply open your debugger (gdb for instance), * set a break point at my_soure_file.cpp:225 and then set the condition * to break for n > 100 (e.g. in gdb the command * is cond break_point_number n > 100 and then run the * program. The program should stop a the point in the source file * right where the exception will be thrown at but before the exception * is thrown. Try not to use expression for throw_exception_test that * includes virtual function calls, etc. as most debuggers will not be able to check * these types of conditions in order to stop at a breakpoint. For example, * instead of: \verbatim TEST_FOR_EXCEPTION( obj1->val() > obj2->val(), std::logic_error, "Oh no!" ); \endverbatim * try: \verbatim double obj1_val = obj1->val(), obj2_val = obj2->val(); TEST_FOR_EXCEPTION( obj1_val > obj2_val, std::logic_error, "Oh no!" ); \endverbatim * If the developer goes to the line in the source file that is contained * in the error message of the exception thrown, he/she will see the * underlying condition. * * As an alternative, you can set a breakpoint for any exception thrown * by setting a breakpoint in the function ThrowException_break(). */ #define TEST_FOR_EXCEPTION(throw_exception_test,Exception,msg) \ { \ const bool throw_exception = (throw_exception_test); \ if(throw_exception) { \ TestForException_incrThrowNumber(); \ std::ostringstream omsg; \ omsg \ << __FILE__ << ":" << __LINE__ << ":\n\n" \ << "Throw number = " << TestForException_getThrowNumber() << "\n\n" \ << "Throw test that evaluated to true: "#throw_exception_test << "\n\n" \ << msg; \ const std::string &omsgstr = omsg.str(); \ TestForException_break(omsgstr); \ throw Exception(omsgstr); \ } \ } /** \brief Macro for throwing an exception with breakpointing to ease debugging * * This macro is equivalent to the TEST_FOR_EXCEPTION() macro except * the file name, line number, and test condition are not printed. */ #define TEST_FOR_EXCEPTION_PURE_MSG(throw_exception_test,Exception,msg) \ { \ const bool throw_exception = (throw_exception_test); \ if(throw_exception) { \ TestForException_incrThrowNumber(); \ std::ostringstream omsg; \ omsg << msg; \ omsg << "\n\nThrow number = " << TestForException_getThrowNumber() << "\n\n"; \ const std::string &omsgstr = omsg.str(); \ TestForException_break(omsgstr); \ throw Exception(omsgstr); \ } \ } /** \brief This macro is designed to be a short version of * TEST_FOR_EXCEPTION() that is easier to call. * * @param throw_exception_test * [in] Test for when to throw the exception. This can and * should be an expression that may mean something to the user. * The text verbatim of this expression is included in the * formed error string. * * \note The exception thrown is std::logic_error. */ #define TEST_FOR_EXCEPT(throw_exception_test) \ TEST_FOR_EXCEPTION(throw_exception_test,std::logic_error,"Error!") /** \brief This macro is the same as TEST_FOR_EXCEPTION() except that the * exception will be caught, the message printed, and then rethrown. * * @param throw_exception_test * [in] See TEST_FOR_EXCEPTION(). * @param Exception * [in] See TEST_FOR_EXCEPTION(). * @param msg [in] See TEST_FOR_EXCEPTION(). * @param out_ptr * [in] If out_ptr!=NULL then *out_ptr will receive * a printout of a line of output that gives the exception type and * the error message that is generated. */ #define TEST_FOR_EXCEPTION_PRINT(throw_exception_test,Exception,msg,out_ptr) \ try { \ TEST_FOR_EXCEPTION(throw_exception_test,Exception,msg); \ } \ catch(const std::exception &except) { \ std::ostream *l_out_ptr = (out_ptr); \ if(l_out_ptr) { \ *l_out_ptr \ << "\nThorwing an std::exception of type \'"<TEST_FOR_EXCEPT() except that the * exception will be caught, the message printed, and then rethrown. * * @param throw_exception_test * [in] See TEST_FOR_EXCEPT(). * @param out_ptr * [in] If out_ptr!=NULL then *out_ptr will receive * a printout of a line of output that gives the exception type and * the error message that is generated. */ #define TEST_FOR_EXCEPT_PRINT(throw_exception_test,out_ptr) \ TEST_FOR_EXCEPTION_PRINT(throw_exception_test,std::logic_error,"Error!",out_ptr) /** \brief This macro intercepts an exception, prints a standardized message including * the current filename and line number, and then throws the exception up the stack * @param exc [in] the exception that has been caught */ #define TEUCHOS_TRACE(exc)\ { \ std::ostringstream omsg; \ omsg << exc.what() << std::endl \ << "caught in " << __FILE__ << ":" << __LINE__ << std::endl ; \ throw std::runtime_error(omsg.str()); \ } //@} #endif // TEUCHOS_TEST_FOR_EXCEPTION_H