forked from hitmen047/Source-PlusPlus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdbg.h
826 lines (688 loc) · 30.6 KB
/
dbg.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#ifndef DBG_H
#define DBG_H
#ifdef _WIN32
#pragma once
#endif
#include "basetypes.h"
#include "dbgflag.h"
#include "platform.h"
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef POSIX
#define __cdecl
#endif
//-----------------------------------------------------------------------------
// dll export stuff
//-----------------------------------------------------------------------------
#ifndef STATIC_TIER0
#ifdef TIER0_DLL_EXPORT
#define DBG_INTERFACE DLL_EXPORT
#define DBG_OVERLOAD DLL_GLOBAL_EXPORT
#define DBG_CLASS DLL_CLASS_EXPORT
#else
#define DBG_INTERFACE DLL_IMPORT
#define DBG_OVERLOAD DLL_GLOBAL_IMPORT
#define DBG_CLASS DLL_CLASS_IMPORT
#endif
#else // BUILD_AS_DLL
#define DBG_INTERFACE extern
#define DBG_OVERLOAD
#define DBG_CLASS
#endif // BUILD_AS_DLL
class Color;
//-----------------------------------------------------------------------------
// Usage model for the Dbg library
//
// 1. Spew.
//
// Spew can be used in a static and a dynamic mode. The static
// mode allows us to display assertions and other messages either only
// in debug builds, or in non-release builds. The dynamic mode allows us to
// turn on and off certain spew messages while the application is running.
//
// Static Spew messages:
//
// Assertions are used to detect and warn about invalid states
// Spews are used to display a particular status/warning message.
//
// To use an assertion, use
//
// Assert( (f == 5) );
// AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) );
// AssertFunc( (f == 5), BadFunc() );
// AssertEquals( f, 5 );
// AssertFloatEquals( f, 5.0f, 1e-3 );
//
// The first will simply report that an assertion failed on a particular
// code file and line. The second version will display a print-f formatted message
// along with the file and line, the third will display a generic message and
// will also cause the function BadFunc to be executed, and the last two
// will report an error if f is not equal to 5 (the last one asserts within
// a particular tolerance).
//
// To use a warning, use
//
// Warning("Oh I feel so %s all over\n", "yummy");
//
// Warning will do its magic in only Debug builds. To perform spew in *all*
// builds, use RelWarning.
//
// Three other spew types, Msg, Log, and Error, are compiled into all builds.
// These error types do *not* need two sets of parenthesis.
//
// Msg( "Isn't this exciting %d?", 5 );
// Error( "I'm just thrilled" );
//
// Dynamic Spew messages
//
// It is possible to dynamically turn spew on and off. Dynamic spew is
// identified by a spew group and priority level. To turn spew on for a
// particular spew group, use SpewActivate( "group", level ). This will
// cause all spew in that particular group with priority levels <= the
// level specified in the SpewActivate function to be printed. Use DSpew
// to perform the spew:
//
// DWarning( "group", level, "Oh I feel even yummier!\n" );
//
// Priority level 0 means that the spew will *always* be printed, and group
// '*' is the default spew group. If a DWarning is encountered using a group
// whose priority has not been set, it will use the priority of the default
// group. The priority of the default group is initially set to 0.
//
// Spew output
//
// The output of the spew system can be redirected to an externally-supplied
// function which is responsible for outputting the spew. By default, the
// spew is simply printed using printf.
//
// To redirect spew output, call SpewOutput.
//
// SpewOutputFunc( OutputFunc );
//
// This will cause OutputFunc to be called every time a spew message is
// generated. OutputFunc will be passed a spew type and a message to print.
// It must return a value indicating whether the debugger should be invoked,
// whether the program should continue running, or whether the program
// should abort.
//
// 2. Code activation
//
// To cause code to be run only in debug builds, use DBG_CODE:
// An example is below.
//
// DBG_CODE(
// {
// int x = 5;
// ++x;
// }
// );
//
// Code can be activated based on the dynamic spew groups also. Use
//
// DBG_DCODE( "group", level,
// { int x = 5; ++x; }
// );
//
// 3. Breaking into the debugger.
//
// To cause an unconditional break into the debugger in debug builds only, use DBG_BREAK
//
// DBG_BREAK();
//
// You can force a break in any build (release or debug) using
//
// DebuggerBreak();
//-----------------------------------------------------------------------------
/* Various types of spew messages */
// I'm sure you're asking yourself why SPEW_ instead of DBG_ ?
// It's because DBG_ is used all over the place in windows.h
// For example, DBG_CONTINUE is defined. Feh.
enum SpewType_t
{
SPEW_MESSAGE = 0,
SPEW_WARNING,
SPEW_ASSERT,
SPEW_ERROR,
SPEW_LOG,
SPEW_TYPE_COUNT
};
enum SpewRetval_t
{
SPEW_DEBUGGER = 0,
SPEW_CONTINUE,
SPEW_ABORT
};
/* type of externally defined function used to display debug spew */
typedef SpewRetval_t (*SpewOutputFunc_t)( SpewType_t spewType, const tchar *pMsg );
/* Used to redirect spew output */
DBG_INTERFACE void SpewOutputFunc( SpewOutputFunc_t func );
/* Used to get the current spew output function */
DBG_INTERFACE SpewOutputFunc_t GetSpewOutputFunc( void );
/* This is the default spew fun, which is used if you don't specify one */
DBG_INTERFACE SpewRetval_t DefaultSpewFunc( SpewType_t type, const tchar *pMsg );
/* Same as the default spew func, but returns SPEW_ABORT for asserts */
DBG_INTERFACE SpewRetval_t DefaultSpewFuncAbortOnAsserts( SpewType_t type, const tchar *pMsg );
/* Should be called only inside a SpewOutputFunc_t, returns groupname, level, color */
DBG_INTERFACE const tchar* GetSpewOutputGroup( void );
DBG_INTERFACE int GetSpewOutputLevel( void );
DBG_INTERFACE const Color* GetSpewOutputColor( void );
/* Used to manage spew groups and subgroups */
DBG_INTERFACE void SpewActivate( const tchar* pGroupName, int level );
DBG_INTERFACE bool IsSpewActive( const tchar* pGroupName, int level );
/* Used to display messages, should never be called directly. */
DBG_INTERFACE void _SpewInfo( SpewType_t type, const tchar* pFile, int line );
DBG_INTERFACE SpewRetval_t _SpewMessage( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_INTERFACE SpewRetval_t _DSpewMessage( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 );
DBG_INTERFACE SpewRetval_t ColorSpewMessage( SpewType_t type, const Color *pColor, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 );
DBG_INTERFACE void _ExitOnFatalAssert( const tchar* pFile, int line );
DBG_INTERFACE bool ShouldUseNewAssertDialog();
DBG_INTERFACE bool SetupWin32ConsoleIO();
// Returns true if they want to break in the debugger.
DBG_INTERFACE bool DoNewAssertDialog( const tchar *pFile, int line, const tchar *pExpression );
// Allows the assert dialogs to be turned off from code
DBG_INTERFACE bool AreAllAssertsDisabled();
DBG_INTERFACE void SetAllAssertsDisabled( bool bAssertsEnabled );
// Provides a callback that is called on asserts regardless of spew levels
typedef void (*AssertFailedNotifyFunc_t)( const char *pchFile, int nLine, const char *pchMessage );
DBG_INTERFACE void SetAssertFailedNotifyFunc( AssertFailedNotifyFunc_t func );
DBG_INTERFACE void CallAssertFailedNotifyFunc( const char *pchFile, int nLine, const char *pchMessage );
/* True if -hushasserts was passed on command line. */
DBG_INTERFACE bool HushAsserts();
#if defined( USE_SDL )
DBG_INTERFACE void SetAssertDialogParent( struct SDL_Window *window );
DBG_INTERFACE struct SDL_Window * GetAssertDialogParent();
#endif
/* Used to define macros, never use these directly. */
#ifdef _PREFAST_
// When doing /analyze builds define _AssertMsg to be __analysis_assume. This tells
// the compiler to assume that the condition is true, which helps to suppress many
// warnings. This define is done in debug and release builds.
// The unfortunate !! is necessary because otherwise /analyze is incapable of evaluating
// all of the logical expressions that the regular compiler can handle.
// Include _msg in the macro so that format errors in it are detected.
#define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0)
#define _AssertMsgOnce( _exp, _msg, _bFatal ) do { __analysis_assume( !!(_exp) ); _msg; } while (0)
// Force asserts on for /analyze so that we get a __analysis_assume of all of the constraints.
#define DBGFLAG_ASSERT
#define DBGFLAG_ASSERTFATAL
#define DBGFLAG_ASSERTDEBUG
#else
#define _AssertMsg( _exp, _msg, _executeExp, _bFatal ) \
do { \
if (!(_exp)) \
{ \
_SpewInfo( SPEW_ASSERT, __TFILE__, __LINE__ ); \
SpewRetval_t ret = _SpewMessage("%s", _msg); \
CallAssertFailedNotifyFunc( __TFILE__, __LINE__, _msg ); \
_executeExp; \
if ( ret == SPEW_DEBUGGER && (Plat_IsInDebugSession() || _bFatal)) \
{ \
if ( !ShouldUseNewAssertDialog() || DoNewAssertDialog( __TFILE__, __LINE__, _msg ) ) \
{ \
DebuggerBreak(); \
} \
if ( _bFatal ) \
{ \
_ExitOnFatalAssert( __TFILE__, __LINE__ ); \
} \
} \
} \
} while (0)
#define _AssertMsgOnce( _exp, _msg, _bFatal ) \
do { \
static bool fAsserted; \
if (!fAsserted ) \
{ \
_AssertMsg( _exp, _msg, (fAsserted = true), _bFatal ); \
} \
} while (0)
#endif
/* Spew macros... */
// AssertFatal macros
// AssertFatal is used to detect an unrecoverable error condition.
// If enabled, it may display an assert dialog (if DBGFLAG_ASSERTDLG is turned on or running under the debugger),
// and always terminates the application
#ifdef DBGFLAG_ASSERTFATAL
#define AssertFatal( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), true )
#define AssertFatalOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), true )
#define AssertFatalMsg( _exp, _msg, ... ) _AssertMsg( _exp, (const tchar *)CDbgFmtMsg( _msg, ##__VA_ARGS__ ), ((void)0), true )
#define AssertFatalMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, true )
#define AssertFatalFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: " _T(#_exp), _f, true )
#define AssertFatalEquals( _exp, _expectedValue ) AssertFatalMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) )
#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) AssertFatalMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) )
#define VerifyFatal( _exp ) AssertFatal( _exp )
#define VerifyEqualsFatal( _exp, _expectedValue ) AssertFatalEquals( _exp, _expectedValue )
#define AssertFatalMsg1( _exp, _msg, a1 ) AssertFatalMsg( _exp, _msg, a1 )
#define AssertFatalMsg2( _exp, _msg, a1, a2 ) AssertFatalMsg( _exp, _msg, a1, a2 )
#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) AssertFatalMsg( _exp, _msg, a1, a2, a3 )
#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4 )
#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5 )
#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6 )
#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 )
#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 )
#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertFatalMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 )
#else // DBGFLAG_ASSERTFATAL
#define AssertFatal( _exp ) ((void)0)
#define AssertFatalOnce( _exp ) ((void)0)
#define AssertFatalMsg( _exp, _msg ) ((void)0)
#define AssertFatalMsgOnce( _exp, _msg ) ((void)0)
#define AssertFatalFunc( _exp, _f ) ((void)0)
#define AssertFatalEquals( _exp, _expectedValue ) ((void)0)
#define AssertFatalFloatEquals( _exp, _expectedValue, _tol ) ((void)0)
#define VerifyFatal( _exp ) (_exp)
#define VerifyEqualsFatal( _exp, _expectedValue ) (_exp)
#define AssertFatalMsg1( _exp, _msg, a1 ) ((void)0)
#define AssertFatalMsg2( _exp, _msg, a1, a2 ) ((void)0)
#define AssertFatalMsg3( _exp, _msg, a1, a2, a3 ) ((void)0)
#define AssertFatalMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0)
#define AssertFatalMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0)
#define AssertFatalMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0)
#define AssertFatalMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0)
#define AssertFatalMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0)
#define AssertFatalMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0)
#endif // DBGFLAG_ASSERTFATAL
// Assert macros
// Assert is used to detect an important but survivable error.
// It's only turned on when DBGFLAG_ASSERT is true.
#ifdef DBGFLAG_ASSERT
#define Assert( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false )
#define AssertMsg( _exp, _msg, ... ) _AssertMsg( _exp, (const tchar *)CDbgFmtMsg( _msg, ##__VA_ARGS__ ), ((void)0), false )
#define AssertOnce( _exp ) _AssertMsgOnce( _exp, _T("Assertion Failed: ") _T(#_exp), false )
#define AssertMsgOnce( _exp, _msg ) _AssertMsgOnce( _exp, _msg, false )
#define AssertFunc( _exp, _f ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), _f, false )
#define AssertEquals( _exp, _expectedValue ) AssertMsg2( (_exp) == (_expectedValue), _T("Expected %d but got %d!"), (_expectedValue), (_exp) )
#define AssertFloatEquals( _exp, _expectedValue, _tol ) AssertMsg2( fabs((_exp) - (_expectedValue)) <= (_tol), _T("Expected %f but got %f!"), (_expectedValue), (_exp) )
#define Verify( _exp ) Assert( _exp )
#define VerifyMsg1( _exp, _msg, a1 ) AssertMsg1( _exp, _msg, a1 )
#define VerifyMsg2( _exp, _msg, a1, a2 ) AssertMsg2( _exp, _msg, a1, a2 )
#define VerifyMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg3( _exp, _msg, a1, a2, a3 )
#define VerifyEquals( _exp, _expectedValue ) AssertEquals( _exp, _expectedValue )
#define DbgVerify( _exp ) Assert( _exp )
#define AssertMsg1( _exp, _msg, a1 ) AssertMsg( _exp, _msg, a1 )
#define AssertMsg2( _exp, _msg, a1, a2 ) AssertMsg( _exp, _msg, a1, a2 )
#define AssertMsg3( _exp, _msg, a1, a2, a3 ) AssertMsg( _exp, _msg, a1, a2, a3 )
#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) AssertMsg( _exp, _msg, a1, a2, a3, a4 )
#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5 )
#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6 )
#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 )
#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 )
#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) AssertMsg( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 )
#else // DBGFLAG_ASSERT
#define Assert( _exp ) ((void)0)
#define AssertOnce( _exp ) ((void)0)
#define AssertMsg( _exp, _msg, ... ) ((void)0)
#define AssertMsgOnce( _exp, _msg ) ((void)0)
#define AssertFunc( _exp, _f ) ((void)0)
#define AssertEquals( _exp, _expectedValue ) ((void)0)
#define AssertFloatEquals( _exp, _expectedValue, _tol ) ((void)0)
#define Verify( _exp ) (_exp)
#define VerifyMsg1( _exp, _msg, a1 ) (_exp)
#define VerifyMsg2( _exp, _msg, a1, a2 ) (_exp)
#define VerifyMsg3( _exp, _msg, a1, a2, a3 ) (_exp)
#define VerifyEquals( _exp, _expectedValue ) (_exp)
#define DbgVerify( _exp ) (_exp)
#define AssertMsg1( _exp, _msg, a1 ) ((void)0)
#define AssertMsg2( _exp, _msg, a1, a2 ) ((void)0)
#define AssertMsg3( _exp, _msg, a1, a2, a3 ) ((void)0)
#define AssertMsg4( _exp, _msg, a1, a2, a3, a4 ) ((void)0)
#define AssertMsg5( _exp, _msg, a1, a2, a3, a4, a5 ) ((void)0)
#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0)
#define AssertMsg6( _exp, _msg, a1, a2, a3, a4, a5, a6 ) ((void)0)
#define AssertMsg7( _exp, _msg, a1, a2, a3, a4, a5, a6, a7 ) ((void)0)
#define AssertMsg8( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8 ) ((void)0)
#define AssertMsg9( _exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9 ) ((void)0)
#endif // DBGFLAG_ASSERT
// The Always version of the assert macros are defined even when DBGFLAG_ASSERT is not,
// so they will be available even in release.
#define AssertAlways( _exp ) _AssertMsg( _exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false )
#define AssertMsgAlways( _exp, _msg ) _AssertMsg( _exp, _msg, ((void)0), false )
// Stringify a number
#define V_STRINGIFY_INTERNAL(x) #x
// Extra level of indirection needed when passing in a macro to avoid getting the macro name instead of value
#define V_STRINGIFY(x) V_STRINGIFY_INTERNAL(x)
// Macros to help decorate warnings or errors with the location in code
#define FILE_LINE_FUNCTION_STRING __FILE__ "(" V_STRINGIFY(__LINE__) "):" __FUNCTION__ ":"
#define FILE_LINE_STRING __FILE__ "(" V_STRINGIFY(__LINE__) "):"
#define FUNCTION_LINE_STRING __FUNCTION__ "(" V_STRINGIFY(__LINE__) "): "
// Handy define for inserting clickable messages into the build output.
// Use like this:
// #pragma MESSAGE("Some message")
#define MESSAGE(msg) message(__FILE__ "(" V_STRINGIFY(__LINE__) "): " msg)
#if !defined( _X360 ) || !defined( _RETAIL )
/* These are always compiled in */
DBG_INTERFACE void Msg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_INTERFACE void DMsg( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 3, 4 );
DBG_INTERFACE void MsgV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist );
DBG_INTERFACE void Warning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_INTERFACE void DWarning( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 3, 4 );
DBG_INTERFACE void WarningV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist );
DBG_INTERFACE void Log( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_INTERFACE void DLog( const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 3, 4 );
DBG_INTERFACE void LogV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist );
#ifdef Error
// p4.cpp does a #define Error Warning and in that case the Error prototype needs to
// be consistent with the Warning prototype.
DBG_INTERFACE void Error( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
#else
DBG_INTERFACE void NORETURN Error( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_INTERFACE void NORETURN ErrorV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist );
#endif
#else
inline void Msg( ... ) {}
inline void DMsg( ... ) {}
inline void MsgV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {}
inline void Warning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) {}
inline void WarningV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {}
inline void DWarning( ... ) {}
inline void Log( ... ) {}
inline void DLog( ... ) {}
inline void LogV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {}
inline void Error( ... ) {}
inline void ErrorV( PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist ) {}
#endif
// You can use this macro like a runtime assert macro.
// If the condition fails, then Error is called with the message. This macro is called
// like AssertMsg, where msg must be enclosed in parenthesis:
//
// ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) );
#define ErrorIfNot( condition, msg ) \
if ( condition ) \
; \
else \
{ \
Error msg; \
}
#if !defined( _X360 ) || !defined( _RETAIL )
/* A couple of super-common dynamic spew messages, here for convenience */
/* These looked at the "developer" group */
DBG_INTERFACE void DevMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_INTERFACE void DevWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_INTERFACE void DevLog( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
/* default level versions (level 1) */
DBG_OVERLOAD void DevMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_OVERLOAD void DevWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_OVERLOAD void DevLog( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
/* These looked at the "console" group */
DBG_INTERFACE void ConColorMsg( int level, const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 3, 4 );
DBG_INTERFACE void ConMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_INTERFACE void ConWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_INTERFACE void ConLog( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
/* default console version (level 1) */
DBG_OVERLOAD void ConColorMsg( const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_OVERLOAD void ConMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_OVERLOAD void ConWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_OVERLOAD void ConLog( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
/* developer console version (level 2) */
DBG_INTERFACE void ConDColorMsg( const Color& clr, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_INTERFACE void ConDMsg( PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_INTERFACE void ConDWarning( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
DBG_INTERFACE void ConDLog( PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 1, 2 );
/* These looked at the "network" group */
DBG_INTERFACE void NetMsg( int level, PRINTF_FORMAT_STRING const tchar* pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_INTERFACE void NetWarning( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
DBG_INTERFACE void NetLog( int level, PRINTF_FORMAT_STRING const tchar *pMsg, ... ) FMTFUNCTION( 2, 3 );
void ValidateSpew( class CValidator &validator );
#else
inline void DevMsg( ... ) {}
inline void DevWarning( ... ) {}
inline void DevLog( ... ) {}
inline void ConMsg( ... ) {}
inline void ConLog( ... ) {}
inline void NetMsg( ... ) {}
inline void NetWarning( ... ) {}
inline void NetLog( ... ) {}
#endif
DBG_INTERFACE void COM_TimestampedLog( PRINTF_FORMAT_STRING char const *fmt, ... ) FMTFUNCTION( 1, 2 );
/* Code macros, debugger interface */
#ifdef DBGFLAG_ASSERT
#define DBG_CODE( _code ) if (0) ; else { _code }
#define DBG_CODE_NOSCOPE( _code ) _code
#define DBG_DCODE( _g, _l, _code ) if (IsSpewActive( _g, _l )) { _code } else {}
#define DBG_BREAK() DebuggerBreak() /* defined in platform.h */
#else /* not _DEBUG */
#define DBG_CODE( _code ) ((void)0)
#define DBG_CODE_NOSCOPE( _code )
#define DBG_DCODE( _g, _l, _code ) ((void)0)
#define DBG_BREAK() ((void)0)
#endif /* _DEBUG */
//-----------------------------------------------------------------------------
#ifndef _RETAIL
class CScopeMsg
{
public:
CScopeMsg( const char *pszScope )
{
m_pszScope = pszScope;
Msg( "%s { ", pszScope );
}
~CScopeMsg()
{
Msg( "} %s", m_pszScope );
}
const char *m_pszScope;
};
#define SCOPE_MSG( msg ) CScopeMsg scopeMsg( msg )
#else
#define SCOPE_MSG( msg )
#endif
//-----------------------------------------------------------------------------
// Macro to assist in asserting constant invariants during compilation
// This implementation of compile time assert has zero cost (so it can safely be
// included in release builds) and can be used at file scope or function scope.
// We're using an ancient version of GCC that can't quite handle some
// of our complicated templates properly. Use some preprocessor trickery
// to workaround this
#ifdef __GNUC__
#define COMPILE_TIME_ASSERT( pred ) typedef int UNIQUE_ID[ (pred) ? 1 : -1 ]
#else
#if _MSC_VER >= 1600
// If available use static_assert instead of weird language tricks. This
// leads to much more readable messages when compile time assert constraints
// are violated.
#define COMPILE_TIME_ASSERT( pred ) static_assert( pred, "Compile time assert constraint is not true: " #pred )
#else
// Due to gcc bugs this can in rare cases (some template functions) cause redeclaration
// errors when used multiple times in one scope. Fix by adding extra scoping.
#define COMPILE_TIME_ASSERT( pred ) typedef char compile_time_assert_type[(pred) ? 1 : -1];
#endif
#endif
// ASSERT_INVARIANT used to be needed in order to allow COMPILE_TIME_ASSERTs at global
// scope. However the new COMPILE_TIME_ASSERT macro supports that by default.
#define ASSERT_INVARIANT( pred ) COMPILE_TIME_ASSERT( pred )
#ifdef _DEBUG
template<typename DEST_POINTER_TYPE, typename SOURCE_POINTER_TYPE>
inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE* pSource)
{
Assert( static_cast<DEST_POINTER_TYPE>(pSource) == dynamic_cast<DEST_POINTER_TYPE>(pSource) );
return static_cast<DEST_POINTER_TYPE>(pSource);
}
#else
#define assert_cast static_cast
#endif
//-----------------------------------------------------------------------------
// Templates to assist in validating pointers:
// Have to use these stubs so we don't have to include windows.h here.
DBG_INTERFACE void _AssertValidReadPtr( void* ptr, int count = 1 );
DBG_INTERFACE void _AssertValidWritePtr( void* ptr, int count = 1 );
DBG_INTERFACE void _AssertValidReadWritePtr( void* ptr, int count = 1 );
DBG_INTERFACE void AssertValidStringPtr( const tchar* ptr, int maxchar = 0xFFFFFF );
#ifdef DBGFLAG_ASSERT
FORCEINLINE void AssertValidReadPtr( const void* ptr, int count = 1 ) { _AssertValidReadPtr( (void*)ptr, count ); }
FORCEINLINE void AssertValidWritePtr( const void* ptr, int count = 1 ) { _AssertValidWritePtr( (void*)ptr, count ); }
FORCEINLINE void AssertValidReadWritePtr( const void* ptr, int count = 1 ) { _AssertValidReadWritePtr( (void*)ptr, count ); }
#else
FORCEINLINE void AssertValidReadPtr( const void* ptr, int count = 1 ) { }
FORCEINLINE void AssertValidWritePtr( const void* ptr, int count = 1 ) { }
FORCEINLINE void AssertValidReadWritePtr( const void* ptr, int count = 1 ) { }
#define AssertValidStringPtr AssertValidReadPtr
#endif
#define AssertValidThis() AssertValidReadWritePtr(this,sizeof(*this))
//-----------------------------------------------------------------------------
// Macro to protect functions that are not reentrant
#ifdef _DEBUG
class CReentryGuard
{
public:
CReentryGuard(int *pSemaphore)
: m_pSemaphore(pSemaphore)
{
++(*m_pSemaphore);
}
~CReentryGuard()
{
--(*m_pSemaphore);
}
private:
int *m_pSemaphore;
};
#define ASSERT_NO_REENTRY() \
static int fSemaphore##__LINE__; \
Assert( !fSemaphore##__LINE__ ); \
CReentryGuard ReentryGuard##__LINE__( &fSemaphore##__LINE__ )
#else
#define ASSERT_NO_REENTRY()
#endif
//-----------------------------------------------------------------------------
//
// Purpose: Inline string formatter
//
#include "tier0/valve_off.h"
class CDbgFmtMsg
{
public:
CDbgFmtMsg(PRINTF_FORMAT_STRING const tchar *pszFormat, ...) FMTFUNCTION( 2, 3 )
{
va_list arg_ptr;
va_start(arg_ptr, pszFormat);
_vsntprintf(m_szBuf, sizeof(m_szBuf)-1, pszFormat, arg_ptr);
va_end(arg_ptr);
m_szBuf[sizeof(m_szBuf)-1] = 0;
}
operator const tchar *() const
{
return m_szBuf;
}
private:
tchar m_szBuf[256];
};
#include "tier0/valve_on.h"
//-----------------------------------------------------------------------------
//
// Purpose: Embed debug info in each file.
//
#if defined( _WIN32 ) && !defined( _X360 )
#ifdef _DEBUG
#pragma comment(compiler)
#endif
#endif
//-----------------------------------------------------------------------------
//
// Purpose: Wrap around a variable to create a simple place to put a breakpoint
//
#ifdef _DEBUG
template< class Type >
class CDataWatcher
{
public:
const Type& operator=( const Type &val )
{
return Set( val );
}
const Type& operator=( const CDataWatcher<Type> &val )
{
return Set( val.m_Value );
}
const Type& Set( const Type &val )
{
// Put your breakpoint here
m_Value = val;
return m_Value;
}
Type& GetForModify()
{
return m_Value;
}
const Type& operator+=( const Type &val )
{
return Set( m_Value + val );
}
const Type& operator-=( const Type &val )
{
return Set( m_Value - val );
}
const Type& operator/=( const Type &val )
{
return Set( m_Value / val );
}
const Type& operator*=( const Type &val )
{
return Set( m_Value * val );
}
const Type& operator^=( const Type &val )
{
return Set( m_Value ^ val );
}
const Type& operator|=( const Type &val )
{
return Set( m_Value | val );
}
const Type& operator++()
{
return (*this += 1);
}
Type operator--()
{
return (*this -= 1);
}
Type operator++( int ) // postfix version..
{
Type val = m_Value;
(*this += 1);
return val;
}
Type operator--( int ) // postfix version..
{
Type val = m_Value;
(*this -= 1);
return val;
}
// For some reason the compiler only generates type conversion warnings for this operator when used like
// CNetworkVarBase<unsigned tchar> = 0x1
// (it warns about converting from an int to an unsigned char).
template< class C >
const Type& operator&=( C val )
{
return Set( m_Value & val );
}
operator const Type&() const
{
return m_Value;
}
const Type& Get() const
{
return m_Value;
}
const Type* operator->() const
{
return &m_Value;
}
Type m_Value;
};
#else
template< class Type >
class CDataWatcher
{
private:
CDataWatcher(); // refuse to compile in non-debug builds
};
#endif
//-----------------------------------------------------------------------------
#endif /* DBG_H */