1 // Copyright (C) 2003 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_ASSERt_ 4 #define DLIB_ASSERt_ 5 6 #include "config.h" 7 #include <sstream> 8 #include <iosfwd> 9 #include "error.h" 10 11 // ----------------------------- 12 13 // Use some stuff from boost here 14 // (C) Copyright John Maddock 2001 - 2003. 15 // (C) Copyright Darin Adler 2001. 16 // (C) Copyright Peter Dimov 2001. 17 // (C) Copyright Bill Kempf 2002. 18 // (C) Copyright Jens Maurer 2002. 19 // (C) Copyright David Abrahams 2002 - 2003. 20 // (C) Copyright Gennaro Prota 2003. 21 // (C) Copyright Eric Friedman 2003. 22 // License: Boost Software License See LICENSE.txt for the full license. 23 // 24 #ifndef DLIB_BOOST_JOIN 25 #define DLIB_BOOST_JOIN( X, Y ) DLIB_BOOST_DO_JOIN( X, Y ) 26 #define DLIB_BOOST_DO_JOIN( X, Y ) DLIB_BOOST_DO_JOIN2(X,Y) 27 #define DLIB_BOOST_DO_JOIN2( X, Y ) X##Y 28 #endif 29 30 // figure out if the compiler has rvalue references. 31 #if defined(__clang__) 32 # if __has_feature(cxx_rvalue_references) 33 # define DLIB_HAS_RVALUE_REFERENCES 34 # endif 35 # if __has_feature(cxx_generalized_initializers) 36 # define DLIB_HAS_INITIALIZER_LISTS 37 # endif 38 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) 39 # define DLIB_HAS_RVALUE_REFERENCES 40 # define DLIB_HAS_INITIALIZER_LISTS 41 #elif defined(_MSC_VER) && _MSC_VER >= 1800 42 # define DLIB_HAS_INITIALIZER_LISTS 43 # define DLIB_HAS_RVALUE_REFERENCES 44 #elif defined(_MSC_VER) && _MSC_VER >= 1600 45 # define DLIB_HAS_RVALUE_REFERENCES 46 #elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X) 47 # define DLIB_HAS_RVALUE_REFERENCES 48 # define DLIB_HAS_INITIALIZER_LISTS 49 #endif 50 51 #if defined(__APPLE__) && defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402) 52 // Apple has not updated libstdc++ in some time and anything under 4.02 does not have <initializer_list> for sure. 53 # undef DLIB_HAS_INITIALIZER_LISTS 54 #endif 55 56 // figure out if the compiler has static_assert. 57 #if defined(__clang__) 58 # if __has_feature(cxx_static_assert) 59 # define DLIB_HAS_STATIC_ASSERT 60 # endif 61 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) && defined(__GXX_EXPERIMENTAL_CXX0X__) 62 # define DLIB_HAS_STATIC_ASSERT 63 #elif defined(_MSC_VER) && _MSC_VER >= 1600 64 # define DLIB_HAS_STATIC_ASSERT 65 #elif defined(__INTEL_COMPILER) && defined(BOOST_INTEL_STDCXX0X) 66 # define DLIB_HAS_STATIC_ASSERT 67 #endif 68 69 70 // ----------------------------- 71 72 namespace dlib 73 { 74 template <bool value> struct compile_time_assert; 75 template <> struct compile_time_assert<true> { enum {value=1}; }; 76 77 template <typename T, typename U> struct assert_are_same_type; 78 template <typename T> struct assert_are_same_type<T,T> {enum{value=1};}; 79 template <typename T, typename U> struct assert_are_not_same_type {enum{value=1}; }; 80 template <typename T> struct assert_are_not_same_type<T,T> {}; 81 82 template <typename T, typename U> struct assert_types_match {enum{value=0};}; 83 template <typename T> struct assert_types_match<T,T> {enum{value=1};}; 84 } 85 86 87 // gcc 4.8 will warn about unused typedefs. But we use typedefs in some of the compile 88 // time assert macros so we need to make it not complain about them "not being used". 89 #ifdef __GNUC__ 90 #define DLIB_NO_WARN_UNUSED __attribute__ ((unused)) 91 #else 92 #define DLIB_NO_WARN_UNUSED 93 #endif 94 95 // Use the newer static_assert if it's available since it produces much more readable error 96 // messages. 97 #ifdef DLIB_HAS_STATIC_ASSERT 98 #define COMPILE_TIME_ASSERT(expression) static_assert(expression, "Failed assertion") 99 #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.") 100 #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) static_assert(!::dlib::assert_types_match<type1,type2>::value, "These types should NOT be the same.") 101 #else 102 #define COMPILE_TIME_ASSERT(expression) \ 103 DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_CTA, __LINE__)[::dlib::compile_time_assert<(bool)(expression)>::value] 104 105 #define ASSERT_ARE_SAME_TYPE(type1, type2) \ 106 DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AAST, __LINE__)[::dlib::assert_are_same_type<type1,type2>::value] 107 108 #define ASSERT_ARE_NOT_SAME_TYPE(type1, type2) \ 109 DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DLIB_AANST, __LINE__)[::dlib::assert_are_not_same_type<type1,type2>::value] 110 #endif 111 112 // ----------------------------- 113 114 #if defined DLIB_DISABLE_ASSERTS 115 // if DLIB_DISABLE_ASSERTS is on then never enable DLIB_ASSERT no matter what. 116 #undef ENABLE_ASSERTS 117 #endif 118 119 #if !defined(DLIB_DISABLE_ASSERTS) && ( defined DEBUG || defined _DEBUG) 120 // make sure ENABLE_ASSERTS is defined if we are indeed using them. 121 #ifndef ENABLE_ASSERTS 122 #define ENABLE_ASSERTS 123 #endif 124 #endif 125 126 // ----------------------------- 127 128 #ifdef __GNUC__ 129 // There is a bug in version 4.4.5 of GCC on Ubuntu which causes GCC to segfault 130 // when __PRETTY_FUNCTION__ is used within certain templated functions. So just 131 // don't use it with this version of GCC. 132 # if !(__GNUC__ == 4 && __GNUC_MINOR__ == 4 && __GNUC_PATCHLEVEL__ == 5) 133 # define DLIB_FUNCTION_NAME __PRETTY_FUNCTION__ 134 # else 135 # define DLIB_FUNCTION_NAME "unknown function" 136 # endif 137 #elif defined(_MSC_VER) 138 #define DLIB_FUNCTION_NAME __FUNCSIG__ 139 #else 140 #define DLIB_FUNCTION_NAME "unknown function" 141 #endif 142 143 #define DLIBM_CASSERT(_exp,_message) \ 144 {if ( !(_exp) ) \ 145 { \ 146 dlib_assert_breakpoint(); \ 147 std::ostringstream dlib_o_out; \ 148 dlib_o_out << "\n\nError detected at line " << __LINE__ << ".\n"; \ 149 dlib_o_out << "Error detected in file " << __FILE__ << ".\n"; \ 150 dlib_o_out << "Error detected in function " << DLIB_FUNCTION_NAME << ".\n\n"; \ 151 dlib_o_out << "Failing expression was " << #_exp << ".\n"; \ 152 dlib_o_out << std::boolalpha << _message << "\n"; \ 153 throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str()); \ 154 }} 155 156 // This macro is not needed if you have a real C++ compiler. It's here to work around bugs in Visual Studio's preprocessor. 157 #define DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(x) x 158 // Make it so the 2nd argument of DLIB_CASSERT is optional. That is, you can call it like 159 // DLIB_CASSERT(exp) or DLIB_CASSERT(exp,message). 160 #define DLIBM_CASSERT_1_ARGS(exp) DLIBM_CASSERT(exp,"") 161 #define DLIBM_CASSERT_2_ARGS(exp,message) DLIBM_CASSERT(exp,message) 162 #define DLIBM_GET_3TH_ARG(arg1, arg2, arg3, ...) arg3 163 #define DLIBM_CASSERT_CHOOSER(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_GET_3TH_ARG(__VA_ARGS__, DLIBM_CASSERT_2_ARGS, DLIBM_CASSERT_1_ARGS, DLIB_CASSERT_NEVER_USED)) 164 #define DLIB_CASSERT(...) DLIB_WORKAROUND_VISUAL_STUDIO_BUGS(DLIBM_CASSERT_CHOOSER(__VA_ARGS__)(__VA_ARGS__)) 165 166 167 #ifdef ENABLE_ASSERTS 168 #define DLIB_ASSERT(...) DLIB_CASSERT(__VA_ARGS__) 169 #define DLIB_IF_ASSERT(exp) exp 170 #else 171 #define DLIB_ASSERT(...) {} 172 #define DLIB_IF_ASSERT(exp) 173 #endif 174 175 // ---------------------------------------------------------------------------------------- 176 177 /*!A DLIB_ASSERT_HAS_STANDARD_LAYOUT 178 179 This macro is meant to cause a compiler error if a type doesn't have a simple 180 memory layout (like a C struct). In particular, types with simple layouts are 181 ones which can be copied via memcpy(). 182 183 184 This was called a POD type in C++03 and in C++0x we are looking to check if 185 it is a "standard layout type". Once we can use C++0x we can change this macro 186 to something that uses the std::is_standard_layout type_traits class. 187 See: http://www2.research.att.com/~bs/C++0xFAQ.html#PODs 188 !*/ 189 // Use the fact that in C++03 you can't put non-PODs into a union. 190 #define DLIB_ASSERT_HAS_STANDARD_LAYOUT(type) \ 191 union DLIB_BOOST_JOIN(DAHSL_,__LINE__) { type TYPE_NOT_STANDARD_LAYOUT; }; \ 192 DLIB_NO_WARN_UNUSED typedef char DLIB_BOOST_JOIN(DAHSL2_,__LINE__)[sizeof(DLIB_BOOST_JOIN(DAHSL_,__LINE__))]; 193 194 // ---------------------------------------------------------------------------------------- 195 // ---------------------------------------------------------------------------------------- 196 // ---------------------------------------------------------------------------------------- 197 198 // breakpoints 199 extern "C" 200 { 201 inline void dlib_assert_breakpoint( 202 ) {} 203 /*! 204 ensures 205 - this function does nothing 206 It exists just so you can put breakpoints on it in a debugging tool. 207 It is called only when an DLIB_ASSERT or DLIB_CASSERT fails and is about to 208 throw an exception. 209 !*/ 210 } 211 212 // ----------------------------- 213 214 #include "stack_trace.h" 215 216 #endif // DLIB_ASSERt_ 217 218