// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_ASSERt_ #define DLIB_ASSERt_ #include "config.h" #include <sstream> #include <iosfwd> #include "error.h" // ----------------------------- // Use some stuff from boost here // (C) Copyright John Maddock 2001 - 2003. // (C) Copyright Darin Adler 2001. // (C) Copyright Peter Dimov 2001. // (C) Copyright Bill Kempf 2002. // (C) Copyright Jens Maurer 2002. // (C) Copyright David Abrahams 2002 - 2003. // (C) Copyright Gennaro Prota 2003. // (C) Copyright Eric Friedman 2003. // License: Boost Software License See LICENSE.txt for the full license. #ifndef BOOST_JOIN #define BOOST_JOIN( X, Y ) BOOST_DO_JOIN( X, Y ) #define BOOST_DO_JOIN( X, Y ) BOOST_DO_JOIN2(X,Y) #define BOOST_DO_JOIN2( X, Y ) X##Y #endif // figure out if the compiler has rvalue references. #if defined(__clang__) # if __has_feature(cxx_rvalue_references) # define DLIB_HAS_RVALUE_REFERENCES # endif # if __has_feature(cxx_generalized_initializers) # define DLIB_HAS_INITIALIZER_LISTS # endif #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) # define DLIB_HAS_RVALUE_REFERENCES # define DLIB_HAS_INITIALIZER_LISTS #elif defined(_MSC_VER) && _MSC_VER >= 1800 # define DLIB_HAS_INITIALIZER_LISTS # define DLIB_HAS_RVALUE_REFERENCES #elif defined(_MSC_VER) && _MSC_VER >= 1600 # define DLIB_HAS_RVALUE_REFERENCES #elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X) # define DLIB_HAS_RVALUE_REFERENCES # define DLIB_HAS_INITIALIZER_LISTS #endif #if defined(__APPLE__) && defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) // Apple has not updated libstdc++ in some time and anything under 4.02 does not have <initializer_list> for sure. # undef DLIB_HAS_INITIALIZER_LISTS #endif // figure out if the compiler has static_assert. #if defined(__clang__) # if __has_feature(cxx_static_assert) # define DLIB_HAS_STATIC_ASSERT # endif #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) # define DLIB_HAS_STATIC_ASSERT #elif defined(_MSC_VER) && _MSC_VER >= 1600 # define DLIB_HAS_STATIC_ASSERT #elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X) # define DLIB_HAS_STATIC_ASSERT #endif // ----------------------------- namespace dlib { template <bool value> struct compile_time_assert; template <> struct compile_time_assert<true> { enum {value=1}; }; template <typename T, typename U> struct assert_are_same_type; template <typename T> struct assert_are_same_type<T,T> {enum{value=1};}; template <typename T, typename U> struct assert_are_not_same_type {enum{value=1}; }; template <typename T> struct assert_are_not_same_type<T,T> {}; template <typename T, typename U> struct assert_types_match {enum{value=0};}; template <typename T> struct assert_types_match<T,T> {enum{value=1};}; } // gcc 4.8 will warn about unused typedefs. But we use typedefs in some of the compile // time assert macros so we need to make it not complain about them "not being used". #ifdef __GNUC__ #define DLIB_NO_WARN_UNUSED __attribute__ ((unused)) #else #define DLIB_NO_WARN_UNUSED #endif // Use the newer static_assert if it's available since it produces much more readable error // messages. #ifdef DLIB_HAS_STATIC_ASSERT #define COMPILE_TIME_ASSERT(expression) static_assert(expression, "Failed assertion") #define ASSERT_ARE_SAME_TYPE(type1, type2) static_assert(::dlib::assert_types_match<type1,type2>::value, "These types should be the same but aren't.") #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) static_assert(!::dlib::assert_types_match<type1,type2>::value, "These types should NOT be the same.") #else #define COMPILE_TIME_ASSERT(expression) \ DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value] #define ASSERT_ARE_SAME_TYPE(type1, type2) \ DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type<type1,type2>::value] #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \ DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type<type1,type2>::value] #endif // ----------------------------- #if defined DLIB_DISABLE_ASSERTS // if DLIB_DISABLE_ASSERTS is on then never enable DLIB_ASSERT no matter what. #undef ENABLE_ASSERTS #endif #if !defined(DLIB_DISABLE_ASSERTS) && ( defined DEBUG || defined _DEBUG) // make sure ENABLE_ASSERTS is defined if we are indeed using them. #ifndef ENABLE_ASSERTS #define ENABLE_ASSERTS #endif #endif // ----------------------------- #ifdef __GNUC__ // There is a bug in version 4.4.5 of GCC on Ubuntu which causes GCC to segfault // when __PRETTY_FUNCTION__ is used within certain templated functions. So just // don't use it with this version of GCC. # if !(__GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 5) # define DLIB_FUNCTION_NAME __PRETTY_FUNCTION__ # else # define DLIB_FUNCTION_NAME "unknown function" # endif #elif defined(_MSC_VER) #define DLIB_FUNCTION_NAME __FUNCSIG__ #else #define DLIB_FUNCTION_NAME "unknown function" #endif #define DLIBM_CASSERT(_exp,_message) \ {if ( !(_exp) ) \ { \ dlib_assert_breakpoint(); \ std::ostringstream dlib_o_out; \ dlib_o_out << "\n\nError detected at line " << __LINE__ << ".\n"; \ dlib_o_out << "Error detected in file " << __FILE__ << ".\n"; \ dlib_o_out << "Error detected in function " << DLIB_FUNCTION_NAME << ".\n\n"; \ dlib_o_out << "Failing expression was " << #_exp << ".\n"; \ dlib_o_out << std::boolalpha << _message << "\n"; \ throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str()); \ }} // This macro is not needed if you have a real C++ compiler. It's here to work around bugs in Visual Studio's preprocessor. #define DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(x) x // Make it so the 2nd argument of DLIB_CASSERT is optional. That is, you can call it like // DLIB_CASSERT(exp) or DLIB_CASSERT(exp,message). #define DLIBM_CASSERT_1_ARGS(exp) DLIBM_CASSERT(exp,"") #define DLIBM_CASSERT_2_ARGS(exp,message) DLIBM_CASSERT(exp,message) #define DLIBM_GET_3TH_ARG(arg1, arg2, arg3, ...) arg3 #define DLIBM_CASSERT_CHOOSER(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_GET_3TH_ARG(__VA_ARGS__, DLIBM_CASSERT_2_ARGS, DLIBM_CASSERT_1_ARGS)) #define DLIB_CASSERT(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_CASSERT_CHOOSER(__VA_ARGS__)(__VA_ARGS__)) #ifdef ENABLE_ASSERTS #define DLIB_ASSERT(...) DLIB_CASSERT(__VA_ARGS__) #define DLIB_IF_ASSERT(exp) exp #else #define DLIB_ASSERT(...) {} #define DLIB_IF_ASSERT(exp) #endif // ---------------------------------------------------------------------------------------- /*!A DLIB_ASSERT_HAS_STANDARD_LAYOUT This macro is meant to cause a compiler error if a type doesn't have a simple memory layout (like a C struct). In particular, types with simple layouts are ones which can be copied via memcpy(). This was called a POD type in C++03 and in C++0x we are looking to check if it is a "standard layout type". Once we can use C++0x we can change this macro to something that uses the std::is_standard_layout type_traits class. See: http://www2.research.att.com/~bs/C++0xFAQ.html#PODs !*/ // Use the fact that in C++03 you can't put non-PODs into a union. #define DLIB_ASSERT_HAS_STANDARD_LAYOUT(type) \ union BOOST_JOIN(DAHSL_,__LINE__) { type TYPE_NOT_STANDARD_LAYOUT; }; \ DLIB_NO_WARN_UNUSED typedef char BOOST_JOIN(DAHSL2_,__LINE__)[sizeof(BOOST_JOIN(DAHSL_,__LINE__))]; // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // breakpoints extern "C" { inline void dlib_assert_breakpoint( ) {} /*! ensures - this function does nothing It exists just so you can put breakpoints on it in a debugging tool. It is called only when an DLIB_ASSERT or DLIB_CASSERT fails and is about to throw an exception. !*/ } // ----------------------------- #include "stack_trace.h" #endif // DLIB_ASSERt_