From 87875cadda5a850ec2f7ba2d09024369f4bc5a6e Mon Sep 17 00:00:00 2001 From: Beman Dawes Date: Mon, 24 Jan 2011 15:37:13 +0000 Subject: [PATCH] Add BOOST_ASSERT_MSG. Add macros to configure output stream. [SVN r68414] --- assert.html | 74 ++++++++++++++++++++++++++++++----- assert_test.cpp | 45 ++++++++++++++++++++++ include/boost/assert.hpp | 83 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 188 insertions(+), 14 deletions(-) diff --git a/assert.html b/assert.html index a970cef..aa3cbf2 100644 --- a/assert.html +++ b/assert.html @@ -17,36 +17,89 @@   +

+ BOOST_ASSERT
+ BOOST_ASSERT_MSG
+ BOOST_VERIFY

+ +

BOOST_ASSERT

The header <boost/assert.hpp> defines the macro BOOST_ASSERT, which is similar to the standard assert macro defined in <cassert>. - The macro is intended to be used in Boost libraries. + The macro is intended to be used in both Boost libraries and user + code.

By default, BOOST_ASSERT(expr) is equivalent to assert(expr).

-

When the macro BOOST_DISABLE_ASSERTS is defined when <boost/assert.hpp> +

If the macro BOOST_DISABLE_ASSERTS is defined when <boost/assert.hpp> is included, BOOST_ASSERT(expr) is defined as ((void)0). This allows users to selectively disable BOOST_ASSERT without affecting the definition of the standard assert.

-

When the macro BOOST_ENABLE_ASSERT_HANDLER is defined when <boost/assert.hpp> +

If the macro BOOST_ENABLE_ASSERT_HANDLER is defined when <boost/assert.hpp> is included, BOOST_ASSERT(expr) evaluates expr and, if the result is false, evaluates the expression

+

::boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)

+

assertion_failed is declared in <boost/assert.hpp> as

-
-namespace boost
+		
+
namespace boost
 {
-
-void assertion_failed(char const * expr, char const * function, char const * file, long line);
-
+  void assertion_failed(char const * expr, char const * function, char const * file, long line);
 }
 
+

but it is never defined. The user is expected to supply an appropriate definition.

As is the case with <cassert>, <boost/assert.hpp> can be included multiple times in a single translation unit. BOOST_ASSERT will be redefined each time as specified above.

+ +

BOOST_ASSERT_MSG

+

+ The header <boost/assert.hpp> defines the macro BOOST_ASSERT_MSG, + which is similar to the standard assert macro defined in <cassert>, + but with an additional macro parameter supplying an error message. The macro is intended to be used in both Boost libraries + and user code. +

+

BOOST_ASSERT_MSG(expr, msg) is equivalent to + ((void)0) if BOOST_DISABLE_ASSERTS or NDEBUG are + defined or expr evaluates to true. If those + macros and BOOST_ENABLE_ASSERT_MSG_HANDLER are not + defined, and expr evaluates to false, an error + message that includes #expr, msg, BOOST_CURRENT_FUNCTION, + __FILE__, and __LINE__ is sent to output stream + BOOST_ASSERT_MSG_OSTREAM + and std::abort() is called.

+

BOOST_ASSERT_MSG_OSTREAM defines the output stream. It defaults to std::cerr. + Integrated development environments (IDE's) like Microsoft Visual Studio + may produce easier to understand output if messages go to a different + stream, such as std::cout. Users may define BOOST_ASSERT_MSG_OSTREAM before including <boost/assert.hpp> + to specify a different output stream. 

+

If the macro BOOST_ENABLE_ASSERT_MSG_HANDLER is defined when <boost/assert.hpp> + is included, instead of sending a error message to an output + stream, this expression is evaluated

+
+

::boost::assertion_failed_msg(#expr, msg, BOOST_CURRENT_FUNCTION, + __FILE__, __LINE__)

+
+

assertion_failed_msg is declared in <boost/assert.hpp> + as

+
+
namespace boost
+{
+  void assertion_failed_msg(char const * expr, char const * msg, char const * function, char const * file, long line);
+}
+
+
+

but it is never defined. The user is expected to supply an appropriate + definition.

+

As is the case with <cassert>, <boost/assert.hpp> + can be included multiple times in a single translation unit. BOOST_ASSERT_MSG + will be redefined each time as specified above.

+ +

BOOST_VERIFY

<boost/assert.hpp> also defines the macro BOOST_VERIFY. It has exactly the same behavior as BOOST_ASSERT, except that the expression that is passed to BOOST_VERIFY is always @@ -54,8 +107,9 @@ void assertion_failed(char const * expr, char const * function, char const * fil effects; it can also help suppress warnings about unused variables when the only use of the variable is inside an assertion.


- Copyright © 2002, 2007 by Peter Dimov. Distributed under the Boost Software + Copyright © 2002, 2007 by Peter Dimov.  Copyright © 2011 + by Beman Dawes. Distributed under the Boost Software License, Version 1.0. See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt.

- + \ No newline at end of file diff --git a/assert_test.cpp b/assert_test.cpp index 693adc4..a0e1e04 100644 --- a/assert_test.cpp +++ b/assert_test.cpp @@ -2,6 +2,7 @@ // assert_test.cpp - a test for boost/assert.hpp // // Copyright (c) 2002 Peter Dimov and Multi Media Ltd. +// Copyright (2) Beman Dawes 2011 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -20,6 +21,11 @@ void test_default() BOOST_ASSERT(x); BOOST_ASSERT(x == 1); BOOST_ASSERT(&x); + + BOOST_ASSERT_MSG(1, "msg"); + BOOST_ASSERT_MSG(x, "msg"); + BOOST_ASSERT_MSG(x == 1, "msg"); + BOOST_ASSERT_MSG(&x, "msg"); } #define BOOST_DISABLE_ASSERTS @@ -34,13 +40,23 @@ void test_disabled() BOOST_ASSERT(x == 1); BOOST_ASSERT(&x); + BOOST_ASSERT_MSG(1, "msg"); + BOOST_ASSERT_MSG(x, "msg"); + BOOST_ASSERT_MSG(x == 1, "msg"); + BOOST_ASSERT_MSG(&x, "msg"); + BOOST_ASSERT(0); BOOST_ASSERT(!x); BOOST_ASSERT(x == 0); + BOOST_ASSERT_MSG(0, "msg"); + BOOST_ASSERT_MSG(!x, "msg"); + BOOST_ASSERT_MSG(x == 0, "msg"); + void * p = 0; BOOST_ASSERT(p); + BOOST_ASSERT_MSG(p, "msg"); // supress warnings p = &x; @@ -50,11 +66,13 @@ void test_disabled() #undef BOOST_DISABLE_ASSERTS #define BOOST_ENABLE_ASSERT_HANDLER +#define BOOST_ENABLE_ASSERT_MSG_HANDLER #include #include #include int handler_invoked = 0; +int msg_handler_invoked = 0; void boost::assertion_failed(char const * expr, char const * function, char const * file, long line) { @@ -66,11 +84,24 @@ void boost::assertion_failed(char const * expr, char const * function, char cons ++handler_invoked; } +void boost::assertion_failed_msg(char const * expr, char const * msg, char const * function, + char const * file, long line) +{ +#if !defined(BOOST_NO_STDC_NAMESPACE) + using std::printf; +#endif + + printf("Expression: %s Message: %s\nFunction: %s\nFile: %s\nLine: %ld\n\n", + expr, msg, function, file, line); + ++msg_handler_invoked; +} + struct X { static void f() { BOOST_ASSERT(0); + BOOST_ASSERT_MSG(0, "msg f()"); } }; @@ -83,21 +114,35 @@ void test_handler() BOOST_ASSERT(x == 1); BOOST_ASSERT(&x); + BOOST_ASSERT_MSG(1, "msg2"); + BOOST_ASSERT_MSG(x, "msg3"); + BOOST_ASSERT_MSG(x == 1, "msg4"); + BOOST_ASSERT_MSG(&x, "msg5"); + BOOST_ASSERT(0); BOOST_ASSERT(!x); BOOST_ASSERT(x == 0); + BOOST_ASSERT_MSG(0,"msg 0"); + BOOST_ASSERT_MSG(!x, "msg !x"); + BOOST_ASSERT_MSG(x == 0, "msg x == 0"); + void * p = 0; BOOST_ASSERT(p); + BOOST_ASSERT_MSG(p, "msg p"); X::f(); BOOST_ASSERT(handler_invoked == 5); BOOST_TEST(handler_invoked == 5); + + BOOST_ASSERT_MSG(msg_handler_invoked == 5, "msg_handler_invoked count is wrong"); + BOOST_TEST(msg_handler_invoked == 5); } #undef BOOST_ENABLE_ASSERT_HANDLER +#undef BOOST_ENABLE_ASSERT_MSG_HANDLER int main() { diff --git a/include/boost/assert.hpp b/include/boost/assert.hpp index 584a756..a04e2e4 100644 --- a/include/boost/assert.hpp +++ b/include/boost/assert.hpp @@ -1,8 +1,11 @@ // // boost/assert.hpp - BOOST_ASSERT(expr) +// BOOST_ASSERT_MSG(expr, msg) +// BOOST_VERIFY(expr) // // Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd. // Copyright (c) 2007 Peter Dimov +// Copyright (c) Beman Dawes 2011 // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -19,6 +22,10 @@ // boostinspect:naassert_macro // +//--------------------------------------------------------------------------------------// +// BOOST_ASSERT // +//--------------------------------------------------------------------------------------// + #undef BOOST_ASSERT #if defined(BOOST_DISABLE_ASSERTS) @@ -31,18 +38,86 @@ namespace boost { - -void assertion_failed(char const * expr, char const * function, char const * file, long line); // user defined - + void assertion_failed(char const * expr, + char const * function, char const * file, long line); // user defined } // namespace boost -#define BOOST_ASSERT(expr) ((expr)? ((void)0): ::boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)) +#define BOOST_ASSERT(expr) ((expr) \ + ? ((void)0) \ + : ::boost::assertion_failed(#expr, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)) #else # include // .h to support old libraries w/o - effect is the same # define BOOST_ASSERT(expr) assert(expr) #endif +//--------------------------------------------------------------------------------------// +// BOOST_ASSERT_MSG // +//--------------------------------------------------------------------------------------// + +# undef BOOST_ASSERT_MSG + +#if defined(BOOST_DISABLE_ASSERTS) || defined(NDEBUG) + + #define BOOST_ASSERT_MSG(expr, msg) ((void)0) + +#elif defined(BOOST_ENABLE_ASSERT_MSG_HANDLER) + + #include + + namespace boost + { + void assertion_failed_msg(char const * expr, char const * msg, + char const * function, char const * file, long line); // user defined + } // namespace boost + + #define BOOST_ASSERT_MSG(expr, msg) ((expr) \ + ? ((void)0) \ + : ::boost::assertion_failed_msg(#expr, msg, BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)) + +#else + #ifndef BOOST_ASSERT_HPP + #define BOOST_ASSERT_HPP + #include + #include + #include + + // IDE's like Visual Studio perform better if output goes to std::cout or + // some other stream, so allow user to configure output stream: + #ifndef BOOST_ASSERT_MSG_OSTREAM + # define BOOST_ASSERT_MSG_OSTREAM std::cerr + #endif + + namespace boost + { + namespace assertion + { + namespace detail + { + inline void assertion_failed_msg(char const * expr, char const * msg, char const * function, + char const * file, long line) + { + BOOST_ASSERT_MSG_OSTREAM + << "***** Internal Program Error - assertion (" << expr << ") failed in " + << function << ":\n" + << file << '(' << line << "): " << msg << std::endl; + std::abort(); + } + } // detail + } // assertion + } // detail + #endif + + #define BOOST_ASSERT_MSG(expr, msg) ((expr) \ + ? ((void)0) \ + : ::boost::assertion::detail::assertion_failed_msg(#expr, msg, \ + BOOST_CURRENT_FUNCTION, __FILE__, __LINE__)) +#endif + +//--------------------------------------------------------------------------------------// +// BOOST_VERIFY // +//--------------------------------------------------------------------------------------// + #undef BOOST_VERIFY #if defined(BOOST_DISABLE_ASSERTS) || ( !defined(BOOST_ENABLE_ASSERT_HANDLER) && defined(NDEBUG) )