From: <ric...@us...> - 2013-08-06 22:56:33
|
Revision: 1191 http://sourceforge.net/p/loki-lib/code/1191 Author: rich_sposato Date: 2013-08-06 22:56:31 +0000 (Tue, 06 Aug 2013) Log Message: ----------- Improved SmartAssert component. Modified Paths: -------------- trunk/Loki.sln trunk/include/loki/SmartAssert.hpp trunk/src/SmartAssert.cpp trunk/test/SmartAssert/SmartAssert.cbp trunk/test/SmartAssert/main.cpp Modified: trunk/Loki.sln =================================================================== --- trunk/Loki.sln 2013-06-24 06:10:50 UTC (rev 1190) +++ trunk/Loki.sln 2013-08-06 22:56:31 UTC (rev 1191) @@ -115,8 +115,6 @@ {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} = {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ThreadLocal", "test\ThreadLocal\ThreadLocal.vcxproj", "{27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Lockable", "test\Lockable\Lockable.vcxproj", "{22A34627-1480-4180-A8B6-4C05E77E27F8}" ProjectSection(ProjectDependencies) = postProject {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} = {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} @@ -127,13 +125,15 @@ {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} = {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "library", "src\Library.vcxproj", "{CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Library", "src\Library.vcxproj", "{CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SmartAssert", "test\SmartAssert\SmartAssert.vcxproj", "{DA7BBAE5-1C1A-4B5E-ABF1-2B5090DB2988}" ProjectSection(ProjectDependencies) = postProject {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} = {CBDB8E7A-4286-4AE3-A190-BA33D7C53FF0} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ThreadLocal", "test\ThreadLocal\ThreadLocal.vcxproj", "{27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -232,10 +232,6 @@ {0605A820-D075-48AC-ABB6-D3FF05D5CD1F}.Debug|Win32.Build.0 = Debug|Win32 {0605A820-D075-48AC-ABB6-D3FF05D5CD1F}.Release|Win32.ActiveCfg = Release|Win32 {0605A820-D075-48AC-ABB6-D3FF05D5CD1F}.Release|Win32.Build.0 = Release|Win32 - {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Debug|Win32.ActiveCfg = Debug|Win32 - {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Debug|Win32.Build.0 = Debug|Win32 - {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Release|Win32.ActiveCfg = Release|Win32 - {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Release|Win32.Build.0 = Release|Win32 {22A34627-1480-4180-A8B6-4C05E77E27F8}.Debug|Win32.ActiveCfg = Debug|Win32 {22A34627-1480-4180-A8B6-4C05E77E27F8}.Debug|Win32.Build.0 = Debug|Win32 {22A34627-1480-4180-A8B6-4C05E77E27F8}.Release|Win32.ActiveCfg = Release|Win32 @@ -252,6 +248,10 @@ {DA7BBAE5-1C1A-4B5E-ABF1-2B5090DB2988}.Debug|Win32.Build.0 = Debug|Win32 {DA7BBAE5-1C1A-4B5E-ABF1-2B5090DB2988}.Release|Win32.ActiveCfg = Release|Win32 {DA7BBAE5-1C1A-4B5E-ABF1-2B5090DB2988}.Release|Win32.Build.0 = Release|Win32 + {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Debug|Win32.ActiveCfg = Debug|Win32 + {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Debug|Win32.Build.0 = Debug|Win32 + {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Release|Win32.ActiveCfg = Release|Win32 + {27CB0BB1-1754-46AB-A8C6-697D1B9B9C41}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE Modified: trunk/include/loki/SmartAssert.hpp =================================================================== --- trunk/include/loki/SmartAssert.hpp 2013-06-24 06:10:50 UTC (rev 1190) +++ trunk/include/loki/SmartAssert.hpp 2013-08-06 22:56:31 UTC (rev 1191) @@ -104,8 +104,8 @@ @endcode @par Setting the Severity Level - Assertions treat all error conditions as an excuse to commit suicide. That - one-size-fits-all solution seems overly drastic for minor errors. At least + Typical assertions treat all error conditions as an excuse to commit suicide. + That one-size-fits-all solution seems overly drastic for minor errors. At least SmartAssert gives the developer more detailed output to help understand why the program died. @@ -153,20 +153,15 @@ @par Write Your Own Policy. Many parts of Loki were implemented using policy-based software design, and SmartAssert follows that tradition. SmartAssert has a default policy that - mimics the behaviors of assert. If you want to make your own policy class, - write that class to have the same function signatures as - CommandLineAssertPolicy, and use the LOKI_SMART_ASSERT_POLICIED macro instead - of LOKI_SMART_ASSERT. + mimics the behaviors of assert. You can implement your own policies to handle + assertions by making a class with the function signatures shown below. If you + write your own policy class, you should also use the LOKI_SMART_ASSERT_POLICIED + macro, and not the LOKI_SMART_ASSERT macro. - @par Potential Policies - - To call a special debugger rather than the default one. - - To send output to a log file instead of to cout. - - To create a popup dialog box to ask the user. - - To attempt last moment cleanup before the program dies. - @code class MyPolicy { + static bool FixedProblem( const SmartAssertBase * asserter ); static void Output( const SmartAssertBase * asserter ); static void Debugger( const SmartAssertBase * asserter ); static SmartAssertBase::UserResponse AskUser( const SmartAssertBase * asserter ); @@ -175,6 +170,16 @@ LOKI_SMART_ASSERT_POLICIED( cond, MyPolicy ); @endcode + @par Potential Policies You Can Create + - To provide a different output message than the default one. + - To call a special debugger rather than the default one. + - To send output to a log file, syslog, or cout, instead of to cerr. + - To create a popup dialog box to ask the user. + - To attempt last moment cleanup before the program dies. + - To correct the problem. + - To fix data invariants caused by the problem. + - Handle assertion by throwing exception. + @par Thread Safety. Each SmartAssert object is declared locally within a function, so it is only accessible by the thread executing it. However, each SmartAssert makes its @@ -239,6 +244,7 @@ LongDouble }; + /// Provides human readable name of data type. static const char * GetName( DataTypeTag tag ); /// @union DataValue Can be configured as any primitive data type. @@ -285,7 +291,11 @@ DataValue( const double v ) : m_double( v ) {} DataValue( const long double v ) : m_l_double( v ) {} - void Output( DataTypeTag type ) const; + /** Sends output of datatype and value to cerr or cout. + @param type What type of data is in the union. + @param use_cerr True to send output to standard error instead of standard out. + */ + void Output( DataTypeTag type, bool use_cerr ) const; }; AssertInfo() : m_type( Unknown ), m_value(), m_next( nullptr ) {} @@ -309,11 +319,13 @@ AssertInfo( double v ) : m_type( Double ), m_value( v ), m_next( nullptr ) {} AssertInfo( long double v ) : m_type( LongDouble ), m_value( v ), m_next( nullptr ) {} - /// Function provides default output action. - void Output() const; + /** Provides default output action. + @param use_cerr True to send output to standard error instead of standard out. + */ + void Output( bool use_cerr ) const; - DataTypeTag m_type; ///< What type of data this stores. - DataValue m_value; ///< Value of that data. + DataTypeTag m_type; ///< What type of data this stores. + DataValue m_value; ///< Value of that data. mutable const AssertInfo * m_next; ///< Pointer to next piece of info, if any. }; @@ -337,7 +349,7 @@ AssertContext( const char * description, const char * value ); /// Function provides default output action. - void Output() const; + void Output( bool use_cerr ) const; unsigned int m_line; ///< Line number within file. const char * m_value; ///< Pointer to either filename or function name. @@ -383,14 +395,16 @@ static const char * const LineDesc; static const char * const FunctionDesc; - mutable const AssertContext * m_context; /// Linked-list of contexts of where assertion occurred. - mutable const AssertInfo * m_info; ///< Linked-list of values provided for output purposes. - SeverityLevel m_level; ///< How bad is this assertion? - bool * m_ignore; ///< Pointer to ignore-always flag. - const char * m_expression; ///< Pointer to C-style string of failed assertion expression. - const char * m_message; ///< Simple message made by developer. - bool m_handled; ///< True if this assertion was handled before destructor. + /// @note All the variables are public so developers can access them through policy classes. + mutable const AssertContext * m_context; ///< Linked-list of contexts of where assertion occurred. + mutable const AssertInfo * m_info; ///< Linked-list of values provided for output purposes. + SeverityLevel m_level; ///< How bad is this assertion? + bool * m_ignore; ///< Pointer to ignore-always flag. + const char * m_expression; ///< Pointer to C-style string of failed assertion expression. + const char * m_message; ///< Simple message made by developer. + bool m_handled; ///< True if this assertion was handled before destructor. + protected: /// Default constructor is used for release builds. It ignores assertions. @@ -414,34 +428,38 @@ /// Called to handle assertion failure. void HandleFailure(); - /// Default implementation of code to output information about assertion. +private: + + /// @note Virtual functions are private to prevent policy classes from using them. + + /// Calls policy class to find out if host program fixed problem. + virtual bool FixedProblem() const = 0; + + /// Calls policy class to output information about assertion. virtual void CallOutput() const; - /// Default implementation of code to call debugger. - virtual void CallDebugger() const; + /// Calls policy class to invoke debugger. + virtual void CallDebugger() const = 0; - /// Default implementation of code to ask user what to do. - virtual UserResponse AskUser() const; + /// Calls policy class to ask user what to do. + virtual UserResponse AskUser() const = 0; - /// Default implementation of code to abort program. + /// Calls policy class to abort program. virtual void AbortNow() const; - - /// Ignore-always flag used by assertions created in release builds. - static bool s_alwaysIgnore; }; // --------------------------------------------------------------------- -/** @class CommandLineAssertPolicy Default policy for command line programs. - Developers can implement their own policies to handle assertions by making a - class with the same function signatures as this class. If you write your own - policy class, you should also use the LOKI_SMART_ASSERT_POLICIED macro, and - not the LOKI_SMART_ASSERT macro. +/** @class CoutAssertPolicy This is a policy for command line programs. It + sends assertion messages to the standard output stream, std::cout. */ -class CommandLineAssertPolicy +class CoutAssertPolicy { public: + /// SmartAssert will ignore error if this returns true. + static bool FixedProblem( const SmartAssertBase * asserter ); + /// Displays information about assertion to the user. static void Output( const SmartAssertBase * asserter ); @@ -458,6 +476,24 @@ // --------------------------------------------------------------------- +/** @class CerrAssertPolicy This is a policy for command line programs. It + sends assertion messages to the standard error stream, std::cerr. This is + the default policy for SmartAssert. +*/ +class CerrAssertPolicy : public CoutAssertPolicy +{ +public: + + /// Displays information about assertion to the user. + static void Output( const SmartAssertBase * asserter ); + + /// Asks user how to handle assertion. + static SmartAssertBase::UserResponse AskUser( const SmartAssertBase * asserter ); + +}; + +// --------------------------------------------------------------------- + /** @class class SmartAssert */ template< class AssertPolicy > @@ -486,7 +522,10 @@ /// Called to do non-default actions when assertion fails. void operator ()() { HandleFailure(); } - /// Adds one piece of information to assertion, generally a variable or result of function call. + /** Adds one piece of information to assertion, generally a variable or result of function call. + This function relies on conversion constructors in AssertInfo to create an AssertInfo from a + single variable. + */ SmartAssert & operator ()( const AssertInfo & info ) { return static_cast< SmartAssert & >( AddInfo( info ) ); @@ -500,21 +539,33 @@ private: + /// @note Virtual functions are private to prevent policy classes from using them. + + /// Calls policy class to find out if host program fixed problem. + virtual bool FixedProblem() const + { + return AssertPolicy::FixedProblem( dynamic_cast< const SmartAssertBase * >( this ) ); + } + + /// Calls policy class to output information about assertion. virtual void CallOutput() const { AssertPolicy::Output( dynamic_cast< const SmartAssertBase * >( this ) ); } + /// Calls policy class to invoke debugger. virtual void CallDebugger() const { AssertPolicy::Debugger( dynamic_cast< const SmartAssertBase * >( this ) ); } + /// Calls policy class to ask user what to do. virtual SmartAssertBase::UserResponse AskUser() const { return AssertPolicy::AskUser( dynamic_cast< const SmartAssertBase * >( this ) ); } + /// Calls policy class to abort program. virtual void AbortNow() const { AssertPolicy::AbortNow( dynamic_cast< const SmartAssertBase * >( this ) ); @@ -603,9 +654,9 @@ #define LOKI_MAKE_SMART_ASSERT( class_name, ignore_var_name, expr ) \ static bool ignore_var_name = false; \ - class class_name : public ::Loki::SmartAssert< ::Loki::CommandLineAssertPolicy > \ + class class_name : public ::Loki::SmartAssert< ::Loki::CerrAssertPolicy > \ { public: \ - typedef ::Loki::SmartAssert< ::Loki::CommandLineAssertPolicy > BaseClass; \ + typedef ::Loki::SmartAssert< ::Loki::CerrAssertPolicy > BaseClass; \ class_name( bool * ignore, const char * expression ) \ : BaseClass( ignore, expression ) {} \ virtual ~class_name() {} \ @@ -621,7 +672,7 @@ #else #define LOKI_SMART_ASSERT( expr ) \ if ( true ) ; else \ - ::Loki::SmartAssert< ::Loki::CommandLineAssertPolicy >() + ::Loki::SmartAssert< ::Loki::CerrAssertPolicy >() // Do nothing. Compiler should optimize away the else branch. #endif Modified: trunk/src/SmartAssert.cpp =================================================================== --- trunk/src/SmartAssert.cpp 2013-06-24 06:10:50 UTC (rev 1190) +++ trunk/src/SmartAssert.cpp 2013-08-06 22:56:31 UTC (rev 1191) @@ -51,7 +51,7 @@ namespace Loki { -bool SmartAssertBase::s_alwaysIgnore = true; +static bool s_alwaysIgnore = true; const char * const SmartAssertBase::FileDesc = "file"; const char * const SmartAssertBase::LineDesc = "line"; @@ -92,119 +92,121 @@ // --------------------------------------------------------------------- -void AssertInfo::DataValue::Output( DataTypeTag theType ) const +void AssertInfo::DataValue::Output( DataTypeTag theType, bool use_cerr ) const { + ::std::basic_ostream< char > & out = ( use_cerr ) ? ::std::cerr : ::std::cout; + switch ( theType ) { case Unknown: { - cout << "\t Error! Unknown data type! " << theType; + out << "\t Error! Unknown data type! " << theType; break; } case Boolean: { const char * message = m_bool ? "true" : "false"; - cout << message; + out << message; break; } case JustChar: { - cout << m_char; + out << m_char; break; } case SignedChar: { - cout << m_s_char; + out << m_s_char; break; } case UnsignedChar: { - cout << m_u_char; + out << m_u_char; break; } case SignedShort: { - cout << m_s_short; + out << m_s_short; break; } case UnsignedShort: { - cout << m_u_short; + out << m_u_short; break; } case JustInt: { - cout << m_int; + out << m_int; break; } case SignedInt: { - cout << m_int; + out << m_int; break; } case UnsignedInt: { - cout << m_u_int; + out << m_u_int; break; } case Long: { - cout << m_long; + out << m_long; break; } case UnsignedLong: { - cout << m_u_long; + out << m_u_long; break; } case LongInt: { - cout << m_s_long_int; + out << m_s_long_int; break; } case UnsignedLongInt: { - cout << m_u_long_int; + out << m_u_long_int; break; } case CharPtr: { - cout << m_p_char; + out << m_p_char; break; } case SignedCharPtr: { - cout << m_p_s_char; + out << m_p_s_char; break; } case UnsignedCharPtr: { - cout << m_p_u_char; + out << m_p_u_char; break; } case VoidPtr: { - cout << m_p_v; + out << m_p_v; break; } case Float: { - cout << m_float; + out << m_float; break; } case Double: { - cout << m_double; + out << m_double; break; } case LongDouble: { - cout << m_l_double; + out << m_l_double; break; } default: { - cout << "\t Error! Undefined data type! " << theType; + out << "\t Error! Undefined data type! " << theType; break; } } @@ -212,11 +214,12 @@ // --------------------------------------------------------------------- -void AssertInfo::Output() const +void AssertInfo::Output( bool use_cerr ) const { - cout << "\t" << GetName( m_type ) << ": "; - m_value.Output( m_type ); - cout << endl; + ::std::basic_ostream< char > & out = ( use_cerr ) ? ::std::cerr : ::std::cout; + out << "\t" << GetName( m_type ) << ": "; + m_value.Output( m_type, use_cerr ); + out << endl; } // --------------------------------------------------------------------- @@ -241,16 +244,17 @@ // --------------------------------------------------------------------- -void AssertContext::Output() const +void AssertContext::Output( bool use_cerr ) const { - cout << m_description << ": "; + ::std::basic_ostream< char > & out = ( use_cerr ) ? ::std::cerr : ::std::cout; + out << m_description << ": "; if ( m_value != nullptr ) { - cout << m_value; + out << m_value; } else { - cout << m_line; + out << m_line; } } @@ -354,28 +358,14 @@ void SmartAssertBase::CallOutput() const { - CommandLineAssertPolicy::Output( this ); + CerrAssertPolicy::Output( this ); } // --------------------------------------------------------------------- -void SmartAssertBase::CallDebugger() const -{ - CommandLineAssertPolicy::Debugger( this ); -} - -// --------------------------------------------------------------------- - -SmartAssertBase::UserResponse SmartAssertBase::AskUser() const -{ - return CommandLineAssertPolicy::AskUser( this ); -} - -// --------------------------------------------------------------------- - void SmartAssertBase::AbortNow() const { - CommandLineAssertPolicy::AbortNow( this ); + CerrAssertPolicy::AbortNow( this ); } // --------------------------------------------------------------------- @@ -383,15 +373,18 @@ void SmartAssertBase::HandleFailure() { m_handled = true; + if ( FixedProblem() ) + { + return; + } try { + CallOutput(); if ( Info_ == m_level ) { - CallOutput(); return; } - CallOutput(); if ( m_level == Fatal_ ) { AbortNow(); @@ -431,57 +424,42 @@ // --------------------------------------------------------------------- -void CommandLineAssertPolicy::Output( const SmartAssertBase * asserter ) +void CommonOutput( const SmartAssertBase * asserter, bool use_cerr ) { - cout << SmartAssertBase::GetName( asserter->m_level ) - << "! Assertion failed! " << asserter->m_expression << endl; + ::std::basic_ostream< char > & out = ( use_cerr ) ? ::std::cerr : ::std::cout; + out << SmartAssertBase::GetName( asserter->m_level ) + << "! Assertion failed! " << asserter->m_expression << endl; if ( nullptr != asserter->m_context ) { - cout << "\t"; - asserter->m_context->Output(); + out << "\t"; + asserter->m_context->Output( use_cerr ); for ( const AssertContext * p = asserter->m_context->m_next; ( p != nullptr ); p = p->m_next ) { - cout << " "; - p->Output(); + out << " "; + p->Output( use_cerr ); } - cout << endl; + out << endl; } if ( ( nullptr != asserter->m_message ) && ( '\0' != *asserter->m_message ) ) { - cout << "\t" << asserter->m_message << endl; + out << "\t" << asserter->m_message << endl; } for ( const AssertInfo * p = asserter->m_info; ( p != nullptr ); p = p->m_next ) { - p->Output(); + p->Output( use_cerr ); } } // --------------------------------------------------------------------- -void CommandLineAssertPolicy::Debugger( const SmartAssertBase * ) +SmartAssertBase::UserResponse CommonAskUser( const SmartAssertBase * asserter, bool use_cerr ) { -#if defined( _WIN32 ) || defined( __WIN32__ ) || defined( WIN32 ) - ::DebugBreak(); // Win32 + ::std::basic_ostream< char > & output = ( use_cerr ) ? ::std::cerr : ::std::cout; -#elif ( defined _MSC_VER ) || ( defined __BORLANDC__) || ( defined __MWERKS__ ) - __asm { int 3 }; - -#elif defined(__GNUC__) // GCC - __asm ("int $0x3"); - -#else - # error "Please supply instruction to DebugBreak (like 'int 3' on Intel processors)" -#endif -} - -// --------------------------------------------------------------------- - -SmartAssertBase::UserResponse CommandLineAssertPolicy::AskUser( const SmartAssertBase * asserter ) -{ const char * prompt = ( SmartAssertBase::Error_ == asserter->m_level ) ? "\tChoose option: (I)gnore This Time, Ignore (E)ach Time, (D)ebug, (A)bort " : "\tChoose option: (I)gnore This Time, Ignore (E)ach Time, (D)ebug "; - ::std::cout << prompt; + output << prompt; bool keep_asking = true; while ( keep_asking ) @@ -502,7 +480,7 @@ } if ( !isspace( ch ) && keep_asking ) // ignore spaces { - std::cout << prompt; + output << prompt; } } @@ -511,8 +489,48 @@ // --------------------------------------------------------------------- -void CommandLineAssertPolicy::AbortNow( const SmartAssertBase * ) +bool CoutAssertPolicy::FixedProblem( const SmartAssertBase * ) { + return false; +} + +// --------------------------------------------------------------------- + +void CoutAssertPolicy::Output( const SmartAssertBase * asserter ) +{ + CommonOutput( asserter, false ); +} + +// --------------------------------------------------------------------- + +void CoutAssertPolicy::Debugger( const SmartAssertBase * ) +{ +#if defined( _WIN32 ) || defined( __WIN32__ ) || defined( WIN32 ) + ::DebugBreak(); // Win32 + +#elif ( defined _MSC_VER ) || ( defined __BORLANDC__) || ( defined __MWERKS__ ) + __asm { int 3 }; + +#elif defined(__GNUC__) // GCC + __asm ("int $0x3"); + +#else + # error "Please supply instruction to DebugBreak (like 'int 3' on Intel processors)" +#endif +} + +// --------------------------------------------------------------------- + +SmartAssertBase::UserResponse CoutAssertPolicy::AskUser( const SmartAssertBase * asserter ) +{ + const SmartAssertBase::UserResponse reply = CommonAskUser( asserter, false ); + return reply; +} + +// --------------------------------------------------------------------- + +void CoutAssertPolicy::AbortNow( const SmartAssertBase * ) +{ // This might be a good time to call any cleanup services, // and to log any useful information to a file. abort(); @@ -520,6 +538,21 @@ // --------------------------------------------------------------------- +void CerrAssertPolicy::Output( const SmartAssertBase * asserter ) +{ + CommonOutput( asserter, true ); +} + +// --------------------------------------------------------------------- + +SmartAssertBase::UserResponse CerrAssertPolicy::AskUser( const SmartAssertBase * asserter ) +{ + const SmartAssertBase::UserResponse reply = CommonAskUser( asserter, true ); + return reply; +} + +// --------------------------------------------------------------------- + #if defined( _MSC_VER ) #pragma warning( pop ) #endif Modified: trunk/test/SmartAssert/SmartAssert.cbp =================================================================== (Binary files differ) Modified: trunk/test/SmartAssert/main.cpp =================================================================== --- trunk/test/SmartAssert/main.cpp 2013-06-24 06:10:50 UTC (rev 1190) +++ trunk/test/SmartAssert/main.cpp 2013-08-06 22:56:31 UTC (rev 1191) @@ -37,6 +37,9 @@ #include <iostream> +#include <cassert> + + // --------------------------------------------------------------------- class Bogus { }; @@ -138,6 +141,66 @@ // --------------------------------------------------------------------- +/** @class ListAssertInfoOnSameLine + This policy class demonstrates how to write and use your own policies. + It lists assert info descriptions on the same line as their values. It + assumes that if an AssertInfo type is a C-style string, then it must be + a description of the next AssertInfo value. It also puts a blank at the + start of the output to vertically separate the assertion info from any + previous output by the host program. + */ +class ListAssertInfoOnSameLine : public Loki::CerrAssertPolicy +{ +public: + /// Displays information about assertion to the user. + static void Output( const Loki::SmartAssertBase * asserter ); +}; + +// --------------------------------------------------------------------- + +void ListAssertInfoOnSameLine::Output( const ::Loki::SmartAssertBase * asserter ) +{ + assert( nullptr != asserter ); + + ::std::cerr << ::std::endl << ::Loki::SmartAssertBase::GetName( asserter->m_level ) + << "! Assertion failed! " << asserter->m_expression << ::std::endl; + if ( nullptr != asserter->m_context ) + { + ::std::cerr << "\t"; + asserter->m_context->Output( true ); + for ( const ::Loki::AssertContext * p = asserter->m_context->m_next; ( p != nullptr ); p = p->m_next ) + { + ::std::cerr << " "; + p->Output( true ); + } + ::std::cerr << ::std::endl; + } + if ( ( nullptr != asserter->m_message ) && ( '\0' != *asserter->m_message ) ) + { + ::std::cerr << "\t" << asserter->m_message << ::std::endl; + } + + const char * description = nullptr; + for ( const ::Loki::AssertInfo * p = asserter->m_info; ( p != nullptr ); p = p->m_next ) + { + if ( ( ::Loki::AssertInfo::CharPtr == p->m_type ) + && ( p->m_next != nullptr ) ) + { + description = p->m_value.m_p_char; + p = p->m_next; + } + else + { + description = ""; + } + ::std::cerr << "\t" << Loki::AssertInfo::GetName( p->m_type ) << ": " << description << " ("; + p->m_value.Output( p->m_type, true ); + ::std::cerr << ')' << ::std::endl; + } +} + +// --------------------------------------------------------------------- + int main( int argc, const char * argv[] ) { @@ -156,9 +219,24 @@ int a3 = 3; LOKI_SMART_ASSERT( 0 == argc ).Warn()( a1 )( a2 )( a3 )(); - // Show how to put names of variables into assertion info. - LOKI_SMART_ASSERT( 0 == argc ).Warn()( a1 )( "a1" )( a2 )( "a2" )( a3 )( "a3" )(); + const unsigned int counted = 57; + const char * name = "Darth Cuddles"; + const bool result = true; + // Show how to put variables names into assertion info. + LOKI_SMART_ASSERT( 0 == argc ).Warn()( counted )( "counted" )( name )( "name" )( result )( "result" )(); + // Same as before, but this shows how to use a policy to put variable names on the same line as their values. + LOKI_SMART_ASSERT_POLICIED( 0 == argc, ListAssertInfoOnSameLine ).Warn() + ( counted )( "counted" )( name )( "name" )( result )( "result" )(); + + // Same as before, but this shows how to use a policy to put variable descriptions on the same line as their values. + LOKI_SMART_ASSERT_POLICIED( 0 == argc, ListAssertInfoOnSameLine ).Warn() + ( counted )( "death toll" )( name )( "villain" )( result )( "Does evil lose?" )(); + + // Same as before, but this shows how to mix names/descriptions and unnamed variables in the same assertion output. + LOKI_SMART_ASSERT_POLICIED( 0 == argc, ListAssertInfoOnSameLine ).Warn()( a1 ) + ( counted )( "death toll" )( name )( "villain" )( a3 )( result )( "Does evil lose?" )( a2 )(); + test_data_types( argc, argv ); test_ignore( argc ); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |