1 /** @file gsDebug.h
2 
3     @brief This file contains the debugging and messaging system of G+Smo.
4 
5     This file is part of the G+Smo library.
6 
7     This Source Code Form is subject to the terms of the Mozilla Public
8     License, v. 2.0. If a copy of the MPL was not distributed with this
9     file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11     Author(s): A. Mantzaflaris
12 */
13 
14 
15 // Start DEBUG_GROUP of Doxygen
16 /** @{ */
17 
18 #pragma once
19 
20 #include <iostream>
21 #include <sstream>
22 #include <iomanip>
23 #include <stdexcept>
24 #include <typeinfo>
25 
26 // See also about memory leak detection:
27 // http://msdn.microsoft.com/en-us/library/e5ewb1h3%28v=vs.90%29.aspx
28 #if _MSC_VER //>= 1400
29 #include <crtdbg.h>
30 //#include <errno.h>
31 #endif
32 
33 //#ifdef GISMO_EXTRA_DEBUG
34 //  #include <misc/gsStackWalker.h>
35 //#endif
36 
37 namespace gismo {
38 
39 /** Logging messages:
40  *  gsInfo is ment to be the standard output stream, like for the output of the
41  *  executables. In general, the library should not write to gsInfo.
42  */
43 #define gsInfo std::cout
44 
45 /** Logging messages:
46  *  gsWarn is for warnings, eg, for missing functionality or problem in the input.
47  *
48  *  Note that gsWarn cannot be given as a parameter to another function.
49  */
50 #define gsWarn std::cout<<"Warning: "
51 //#define gsWarn std::cerr
52 
53 /** Logging messages:
54  *  gsDebug and gsDebugVar(.) are for debugging messages and are enabled in debug
55  *  mode only.
56  *
57  *  Note that gsDebug cannot be given as a parameter to another function.
58  */
59 #ifndef  NDEBUG
60 
61     #define gsDebug std::cout<<"GISMO_DEBUG: "
62 
63     #define gsDebugVar(variable) gsDebug << (strrchr(__FILE__, '/') ?          \
64                              strrchr(__FILE__, '/') + 1 : __FILE__) <<":"<<    \
65                               __LINE__<< ", "#variable": \n"<<(variable)<<"\n"
66 #define gsDebugIf(cond,variable) if (cond) gsDebug <<"[ "#cond" ] -- "<<       \
67               (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) \
68                <<":"<<__LINE__<< ", "#variable": \n"<<(variable)<<"\n"
69 #else
70     #define gsDebug if (0) std::cout
71     #define gsDebugVar(variable)
72     #define gsDebugIf(cond,variable)
73 #endif
74 
75 /**
76  *  Used for optional inclusion of .hpp header files in the .h files.
77  *  Allows to drop dependencies on the .hpp files when using
78  *  GISMO_BUILD_LIB for compiling a library instance.
79  *  When compiling as a pure template library CMake will detect
80  *  dependency on .hpp files.
81  */
82 #define GISMO_HPP_HEADER(x) #x
83 
84 /**
85  *  Runtime assertions which display a message
86  *
87  */
88 #ifndef NDEBUG
89 #   define GISMO_ASSERT(cond, message) do if(!(cond)) {std::stringstream _m_;\
90        _m_<<"GISMO_ASSERT `"<<#cond<<"` "<<message<<"\n"<<__FILE__<<", line "\
91         <<__LINE__<<" ("<<__FUNCTION__<<")";                                 \
92        throw std::logic_error(_m_.str()); } while(false)
93 #else
94 #   define GISMO_ASSERT(condition, message)
95 #endif
96 
97 /**
98  *  Runtime check and display error message. This command is the same as
99  *  GISMO_ASSERT but it is executed in release builds as well.
100  *
101  */
102 #define GISMO_ENSURE(cond, message) do if(!(cond)) {std::stringstream _m_;   \
103     _m_<<"GISMO_ENSURE `"<<#cond<<"` "<<message<<"\n"<<__FILE__<<", line "   \
104      <<__LINE__<<" ("<< __FUNCTION__<< ")";                                  \
105     throw std::runtime_error(_m_.str());} while(false)
106 
107 /**
108  *  Denote a variable as unused, used to silence warnings in release
109  *  mode builds.
110  *
111  */
112 #define GISMO_UNUSED(x)  static_cast<void>(x)
113 
114 /**
115  *  Runtime error message
116  *
117  */
118 #define GISMO_ERROR(message) do {std::stringstream _m_; _m_<<"GISMO_ERROR "  \
119     <<message<<"\n"<<__FILE__<<", line " <<__LINE__<<" ("<<__FUNCTION__<<")";\
120     throw std::runtime_error(_m_.str());} while(false)
121 
122 /**
123  *  Runtime "no implementation" error happens when the user calls a
124 
125  *  virtual member function without a default implementation.
126  */
127 
128 // TO DO: for GCC __PRETTY_FUNC__ is better
129 #define GISMO_NO_IMPLEMENTATION {std::stringstream _m_;                            \
130     _m_<<"Virtual member function `"<<__FUNCTION__<<"` has not been implemented\n" \
131      <<__FILE__<<", line "<<__LINE__<<"\n"<<typeid(*this).name();                  \
132     throw std::runtime_error(_m_.str());}
133 
134 /*
135 #ifdef _MSC_VER
136 #include <float.h>
137 template <typename T> int isnan   (T a) {return _isnan(a); }
138 template <typename T> int isfinite(T a){return _finite(a);}
139 template <typename T> bool isinf(T a) {return (_FPCLASS_PINF|_FPCLASS_NINF) & _fpclass(a);}
140  #else
141 #ifdef _INTEL_COMPILER
142 #include <mathimf.h>
143 #else
144 using std::isnan;
145 using std::isfinite;
146 using std::isinf;
147 #endif
148 */
149 /**
150    Check if a floating point number is different than NAN (not a number)
151 
152    See https://en.wikipedia.org/wiki/Floating_point#Special_values
153    and https://en.wikipedia.org/wiki/NaN
154  */
gsIsnumber(T a)155 template <typename T> bool gsIsnumber(T a) {return a == a;}
gsIsnan(T a)156 template <typename T> bool gsIsnan   (T a) {return a != a;}
157 /**
158    Check if a flaoting point number is different than INF
159 
160    See https://en.wikipedia.org/wiki/Floating_point#Special_values
161  */
gsIsfinite(T a)162 template <typename T> bool gsIsfinite(T a) {return  (a - a) == (a - a);}
163 
164 }//namespace gismo
165 
166 /*
167   Disable debug/abort popup windows on MS Windows
168 
169   See http://msdn.microsoft.com/en-us/library/1y71x448.aspx
170 
171   You might also need to disable "error reporting" on your windows
172   system for popup-free runs.
173 */
174 #if _MSC_VER //>= 1400
175 static const int    gismo_CrtSetReportMode = _CrtSetReportMode(
176     _CRT_ASSERT, _CRTDBG_MODE_FILE   );
177 static const _HFILE gismo_CrtSetReportFile = _CrtSetReportFile(
178     _CRT_ASSERT, _CRTDBG_FILE_STDERR );
179 static const int  gismo_set_abort_behavior = _set_abort_behavior(
180     0x0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
181 #endif
182 
183 /*
184   Disable some Warnings
185 */
186 
187 #ifdef _MSC_VER
188 // 4100 - unreferenced formal parameter
189 // 4101 - unreferenced local variable
190 // 4127 - conditional expression is constant (triggered by assertion macros)
191 // 4146 - unary minus operator applied to unsigned type, result still unsigned
192 // 4181 - qualifier applied to reference type ignored
193 // 4211 - nonstandard extension used : redefined extern to static
194 // 4231 - nonstandard extension used: extern before template explicit instantiation
195 // 4244 - 'argument' : conversion from 'type1' to 'type2', possible loss of data
196 // 4251 - needs to have dll-interface to be used by clients of class
197 // 4273 - QtAlignedMalloc, inconsistent DLL linkage
198 // 4275 - non dll-interface base
199 // 4324 - structure was padded due to declspec(align())
200 // 4428 - universal-character-name encountered in source
201 // 4503 - decorated name length exceeded
202 // 4505 - unreferenced local function has been removed
203 // 4512 - assignment operator could not be generated
204 // 4522 - 'class' : multiple assignment operators specified
205 // 4566 - character represented by universal-character-name cannot be represented in the current code page
206 // 4661 - no definition available
207 // 4700 - uninitialized local variable 'xyz' used
208 // 4702 - unreachable code
209 // 4714 - function marked as __forceinline not inlined
210 // 4717 - 'function' : recursive on all control paths, function will cause runtime stack overflow
211 // 4789 - destination of memory copy is too small (for Eigen)
212 // 4996 - 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead.
213 // 4510 - default constructor could not be generated
214 // 4610 - user defined constructor required
215   #pragma warning( push )
216   #pragma warning( disable : 4100 4127 4146 4231 4251 4428 4275 4503 4505 4512 4566 4661 4714 4789 4996 4510 4610)
217 
218 #elif defined __INTEL_COMPILER
219 // 2196 - routine is both "inline" and "noinline" ("noinline" assumed)
220 //        ICC 12 generates this warning even without any inline keyword, when defining class methods 'inline' i.e. inside of class body
221 //        typedef that may be a reference type.
222 // 279  - controlling expression is constant
223 //        ICC 12 generates this warning on assert(constant_expression_depending_on_template_params) and frankly this is a legitimate use case.
224 // 161  - unrecognized pragma
225 // 175  - subscript out of range
226 //        to avoid warnings on #pragma GCC diagnostic
227   #pragma warning push
228   #pragma warning disable 2196 279 161 175
229 
230 #elif defined __clang__
231 // -Wconstant-logical-operand - warning: use of logical && with constant operand; switch to bitwise & or remove constant
232 // -Wbind-to-temporary-copy - warning: Warn about an unusable copy constructor when binding a reference to a temporary
233   #pragma clang diagnostic push
234   #pragma clang diagnostic ignored "-Wconstant-logical-operand"
235   #pragma clang diagnostic ignored "-Wbind-to-temporary-copy"
236 
237 #elif defined __GNUC__ // major version >=4
238 // typedef locally defined but not used [-Wunused-local-typedefs]
239 #if ( __GNUC__>4 || (__GNUC__==4 && __GNUC_MINOR__>7) )
240 #pragma GCC diagnostic ignored "-Wunused-local-typedefs"
241 #endif
242 
243 #if (__cplusplus < 201703L && __GNUC__>6)
244 // mangled name will change in C++17 because the exception
245 // specification is part of a function type [-Wnoexcept-type]
246 #pragma GCC diagnostic ignored "-Wnoexcept-type"
247 #endif
248 
249 #endif
250 
251 
252 /*
253    Compile-time assertions:
254 
255   - in GISMO_STATIC_ASSERT(CONDITION,MSG) the parameter CONDITION
256      must be a compile time boolean expression, and MSG an error
257      message (string)
258 
259    - define GISMO_NO_STATIC_ASSERT to disable them (and save
260      compilation time) in that case, the static assertion is
261      converted to a runtime assertion.
262 
263   - GISMO_STATIC_ASSERT can only be used in function scope
264  */
265 #ifndef GISMO_NO_STATIC_ASSERT
266 
267   #if defined(__GXX_EXPERIMENTAL_CXX0X__) || _MSC_VER >= 1600
268 
269     // Native static_assert is available
270     #define GISMO_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
271 
272   #else // not C++11
273 
274     namespace gismo {
275     namespace internal {
276 
277     template<bool condition> struct static_assertion {};
278     template<> struct static_assertion<true> { enum { STATIC_ASSERTION_FAILED }; };
279 
280     } // end namespace internal
281     } // end namespace gismo
282 
283     // Specialized implementation for MSVC to avoid "conditional
284     // expression is constant" warnings.  This implementation doesn't
285     // appear to work under GCC, hence the multiple implementations.
286     #ifdef _MSC_VER
287 
288       #define GISMO_STATIC_ASSERT(CONDITION,MSG) \
289         {gismo::internal::static_assertion<bool(CONDITION)>::STATIC_ASSERTION_FAILED;}
290 
291     #else
292 
293       #define GISMO_STATIC_ASSERT(CONDITION,MSG) \
294         if (gismo::internal::static_assertion<bool(CONDITION)>::STATIC_ASSERTION_FAILED) {}
295 
296     #endif
297 
298   #endif // not C++11
299 
300 #else // GISMO_NO_STATIC_ASSERT
301 
302 #define GISMO_STATIC_ASSERT(CONDITION,MSG) GISMO_ASSERT(CONDITION, #MSG);
303 
304 #endif // GISMO_NO_STATIC_ASSERT
305 
306 
307 
308 #ifdef GISMO_WARNINGS
309     //#pragma message("G+Smo Warnings ON")
310   #ifdef __GNUC__
311     #define GISMO_DEPRECATED __attribute__((deprecated))
312   #elif defined(_MSC_VER)
313     #define GISMO_DEPRECATED __declspec(deprecated)
314   #else
315     #define GISMO_DEPRECATED
316   #endif
317 #else
318   #define GISMO_DEPRECATED
319 #endif
320 
321 
322 // Next line closes the DEBUG_GROUP of Doxygen
323 /** @} */
324