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 3541 : template< class T > inline std::string className( const T& object )
79 3541 : { 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 0 : template< class T > inline std::string format( const T* data, const size_t num )
94 : {
95 0 : std::ostringstream os;
96 0 : os << num << " " << className( data ) << " @ " << std::hex
97 0 : << (const void*)data << ": 0x";
98 0 : for( size_t i = 0; i < num; ++i )
99 : {
100 0 : if( (i % 8) == 0 )
101 0 : os << " " << std::endl;
102 0 : os << ' ' << data[i];
103 : }
104 0 : 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 0 : template< class T > inline std::string format( const std::vector< T >& data )
127 0 : { return format< T >( &data[0], data.size( )); }
128 :
129 : } // namespace lunchbox
130 :
131 : #ifdef NDEBUG
132 : # ifdef LB_RELEASE_ASSERT
133 : # define LBASSERT(x) \
134 : { \
135 : if( !(x) ) \
136 : LBERROR << "##### Assert: " << #x << " #####" << std::endl \
137 : << lunchbox::forceFlush; \
138 : lunchbox::checkHeap(); \
139 : }
140 : # define LBASSERTINFO(x, info) \
141 : { \
142 : if( !(x) ) \
143 : LBERROR << "##### Assert: " << #x << " [" << info << "] #####" \
144 : << std::endl << lunchbox::forceFlush; \
145 : lunchbox::checkHeap(); \
146 : }
147 : # define LBCHECK(x) { const bool eqOk = x; LBASSERTINFO( eqOk, #x ) }
148 : # else
149 : # define LBASSERT(x)
150 : # define LBASSERTINFO(x, info)
151 : # define LBCHECK(x) { x; }
152 : # endif
153 :
154 : # define LBUNIMPLEMENTED { LBERROR << "Unimplemented code" << std::endl \
155 : << lunchbox::forceFlush; }
156 : # define LBUNREACHABLE { LBERROR << "Unreachable code" << std::endl \
157 : << lunchbox::forceFlush; }
158 : # define LBDONTCALL \
159 : { LBERROR << "Code is not supposed to be called in this context" \
160 : << std::endl << lunchbox::forceFlush; }
161 : # define LBABORT( info ) { \
162 : LBERROR << "##### Abort: " << info << " #####" << std::endl \
163 : << lunchbox::forceFlush; }
164 :
165 : #else // NDEBUG
166 :
167 : # define LBASSERT(x) \
168 : { \
169 : if( !(x) ) \
170 : { \
171 : LBERROR << "Assert: " << #x << " "; \
172 : lunchbox::abort(); \
173 : } \
174 : lunchbox::checkHeap(); \
175 : }
176 : # define LBASSERTINFO(x, info) \
177 : { \
178 : if( !(x) ) \
179 : { \
180 : LBERROR << "Assert: " << #x << " [" << info << "] "; \
181 : lunchbox::abort(); \
182 : } \
183 : lunchbox::checkHeap(); \
184 : }
185 :
186 : # define LBUNIMPLEMENTED \
187 : { LBERROR << "Unimplemented code in " << lunchbox::className( this ) \
188 : << " "; \
189 : lunchbox::abort(); }
190 : # define LBUNREACHABLE \
191 : { LBERROR << "Unreachable code in " << lunchbox::className( this ) \
192 : << " "; \
193 : lunchbox::abort(); }
194 : # define LBDONTCALL \
195 : { LBERROR << "Code is not supposed to be called in this context, type " \
196 : << lunchbox::className( this ) << " " ; \
197 : lunchbox::abort(); }
198 :
199 : # define LBCHECK(x) { const bool eqOk = x; LBASSERTINFO( eqOk, #x ) }
200 : # define LBABORT( info ) { \
201 : LBERROR << "Abort: " << info; \
202 : lunchbox::abort(); }
203 : #endif // NDEBUG
204 :
205 : #define LBSAFECAST( to, in ) static_cast< to >( in ); \
206 : LBASSERT( in == 0 || dynamic_cast< to >( static_cast< to >( in )))
207 :
208 : #endif //LUNCHBOX_DEBUG_H
|