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