Line data Source code
1 :
2 : /* Copyright (c) 2007-2012, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2013, Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #ifndef LUNCHBOX_DEBUG_H
20 : #define LUNCHBOX_DEBUG_H
21 :
22 : #include <lunchbox/defines.h>
23 : #include <lunchbox/log.h>
24 :
25 : #include <typeinfo>
26 :
27 : // assertions
28 : // #define LB_RELEASE_ASSERT
29 :
30 : namespace lunchbox
31 : {
32 : /**
33 : * @internal
34 : * Used to trap into an infinite loop to allow debugging of assertions
35 : */
36 : LUNCHBOX_API void abort();
37 :
38 : /**
39 : * @internal
40 : * Check the consistency of the heap and abort on error (Win32 only).
41 : */
42 : LUNCHBOX_API void checkHeap();
43 :
44 : /**
45 : * Print a textual description of the current system error.
46 : *
47 : * The current system error is OS-specific, e.g., errno or GetLastError().
48 : * @version 1.0
49 : */
50 : LUNCHBOX_API std::ostream& sysError( std::ostream& os );
51 :
52 : /** @return a textual description of the current system error. @version 1.9.1 */
53 : LUNCHBOX_API std::string sysError();
54 :
55 : /**
56 : * Get the current call stack.
57 : *
58 : * May not be implemented on all platforms.
59 : *
60 : * @param skipFrames the number of most recent stack frames to ignore.
61 : * @version 1.9.1
62 : */
63 : LUNCHBOX_API std::string backtrace( const size_t skipFrames );
64 :
65 : /** Print the current call stack. @version 1.0 */
66 : LUNCHBOX_API std::ostream& backtrace( std::ostream& os );
67 :
68 : LUNCHBOX_API std::string demangleTypeID( const char* mangled ); //!< @internal
69 :
70 : #ifdef _WIN32
71 : # pragma warning( disable: 4100 ) // VS Bug
72 : #endif
73 : /** Print the RTTI name of the given class. @version 1.0 */
74 0 : template< class T > inline std::string className( const T* object )
75 0 : { return demangleTypeID( typeid( *object ).name( )); }
76 :
77 : /** Print the RTTI name of the given class. @version 1.0 */
78 3540 : template< class T > inline std::string className( const T& object )
79 3540 : { return demangleTypeID( typeid( object ).name( )); }
80 : #ifdef _WIN32
81 : # pragma warning( default: 4100 )
82 : #endif
83 :
84 : /**
85 : * Format the given array in a human-readable form.
86 : * Depending on the data type, a different formatting may be used.
87 : *
88 : * @param data The pointer to the data to print.
89 : * @param num The number of elements of T to print, for T==void the number of
90 : * bytes.
91 : * @version 1.9.1
92 : */
93 : template< class T > inline std::string format( const T* data, const size_t num )
94 : {
95 : std::ostringstream os;
96 : os << num << " " << className( data ) << " @ " << std::hex
97 : << (const void*)data << ": 0x";
98 : for( size_t i = 0; i < num; ++i )
99 : {
100 : if( (i % 8) == 0 )
101 : os << " " << std::endl;
102 : os << ' ' << data[i];
103 : }
104 : return os.str();
105 : }
106 :
107 : template<> inline std::string format( const uint8_t* data, const size_t num )
108 : {
109 : std::ostringstream os;
110 : os << num << " bytes @ " << std::hex << (const void*)data << ": 0x";
111 : os.precision( 2 );
112 : for( size_t i = 0; i < num; ++i )
113 : {
114 : if( (i % 32) == 0 )
115 : os << " " << std::endl;
116 : else if( (i % 8) == 0 )
117 : os << ' ';
118 : os << ' ' << std::setw(2) << int( data[i] );
119 : }
120 : return os.str();
121 : }
122 :
123 : template<> inline std::string format( const void* data, const size_t num )
124 : { return format( reinterpret_cast< const uint8_t* >( data ), num ); }
125 :
126 : } // namespace lunchbox
127 :
128 : #ifdef NDEBUG
129 : # ifdef LB_RELEASE_ASSERT
130 : # define LBASSERT(x) \
131 : { \
132 : if( !(x) ) \
133 : LBERROR << "##### Assert: " << #x << " #####" << std::endl \
134 : << lunchbox::forceFlush; \
135 : lunchbox::checkHeap(); \
136 : }
137 : # define LBASSERTINFO(x, info) \
138 : { \
139 : if( !(x) ) \
140 : LBERROR << "##### Assert: " << #x << " [" << info << "] #####" \
141 : << std::endl << lunchbox::forceFlush; \
142 : lunchbox::checkHeap(); \
143 : }
144 : # define LBCHECK(x) { const bool eqOk = x; LBASSERTINFO( eqOk, #x ) }
145 : # else
146 : # define LBASSERT(x)
147 : # define LBASSERTINFO(x, info)
148 : # define LBCHECK(x) { x; }
149 : # endif
150 :
151 : # define LBUNIMPLEMENTED { LBERROR << "Unimplemented code" << std::endl \
152 : << lunchbox::forceFlush; }
153 : # define LBUNREACHABLE { LBERROR << "Unreachable code" << std::endl \
154 : << lunchbox::forceFlush; }
155 : # define LBDONTCALL \
156 : { LBERROR << "Code is not supposed to be called in this context" \
157 : << std::endl << lunchbox::forceFlush; }
158 : # define LBABORT( info ) { \
159 : LBERROR << "##### Abort: " << info << " #####" << std::endl \
160 : << lunchbox::forceFlush; }
161 :
162 : #else // NDEBUG
163 :
164 : # define LBASSERT(x) \
165 : { \
166 : if( !(x) ) \
167 : { \
168 : LBERROR << "Assert: " << #x << " "; \
169 : lunchbox::abort(); \
170 : } \
171 : lunchbox::checkHeap(); \
172 : }
173 : # define LBASSERTINFO(x, info) \
174 : { \
175 : if( !(x) ) \
176 : { \
177 : LBERROR << "Assert: " << #x << " [" << info << "] "; \
178 : lunchbox::abort(); \
179 : } \
180 : lunchbox::checkHeap(); \
181 : }
182 :
183 : # define LBUNIMPLEMENTED \
184 : { LBERROR << "Unimplemented code in " << lunchbox::className( this ) \
185 : << " "; \
186 : lunchbox::abort(); }
187 : # define LBUNREACHABLE \
188 : { LBERROR << "Unreachable code in " << lunchbox::className( this ) \
189 : << " "; \
190 : lunchbox::abort(); }
191 : # define LBDONTCALL \
192 : { LBERROR << "Code is not supposed to be called in this context, type " \
193 : << lunchbox::className( this ) << " " ; \
194 : lunchbox::abort(); }
195 :
196 : # define LBCHECK(x) { const bool eqOk = x; LBASSERTINFO( eqOk, #x ) }
197 : # define LBABORT( info ) { \
198 : LBERROR << "Abort: " << info; \
199 : lunchbox::abort(); }
200 : #endif // NDEBUG
201 :
202 : #define LBSAFECAST( to, in ) static_cast< to >( in ); \
203 : LBASSERT( in == 0 || dynamic_cast< to >( static_cast< to >( in )))
204 :
205 : #endif //LUNCHBOX_DEBUG_H
|