00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #ifndef NL_DEBUG_H
00025 #define NL_DEBUG_H
00026
00027 #include <cstdio>
00028
00029 #include "common.h"
00030 #include "log.h"
00031 #include "mutex.h"
00032 #include "mem_displayer.h"
00033 #include "displayer.h"
00034 #include "app_context.h"
00035 #include <set>
00036
00037 namespace NLMISC
00038 {
00039
00040 #ifdef ASSERT_THROW_EXCEPTION
00041 #define ASSERT_THROW_EXCEPTION_CODE(exp) ASSERT_THROW_EXCEPTION_CODE_EX(exp, #exp)
00042 #define ASSERT_THROW_EXCEPTION_CODE_EX(exp, str) if(!(exp)) throw NLMISC::Exception(str" returns false");
00043 #else
00044 #define ASSERT_THROW_EXCEPTION_CODE(exp)
00045 #define ASSERT_THROW_EXCEPTION_CODE_EX(exp, str)
00046 #endif
00047
00055 class CImposterLog
00056 {
00057 private:
00058 typedef CLog *(INelContext::*TAccessor)();
00059
00060
00061 TAccessor _Accessor;
00062 public:
00063 CImposterLog(TAccessor accessor);
00064 CLog* operator -> ();
00065 operator CLog*();
00066 CLog &operator ()();
00067 };
00068
00069
00070
00071
00072
00073
00074
00075
00076 extern CImposterLog ErrorLog;
00077 extern CImposterLog WarningLog;
00078 extern CImposterLog InfoLog;
00079 extern CImposterLog DebugLog;
00080 extern CImposterLog AssertLog;
00081
00082 extern CMemDisplayer *DefaultMemDisplayer;
00083 extern CMsgBoxDisplayer *DefaultMsgBoxDisplayer;
00084
00085
00086
00087
00088
00089
00090
00091 void createDebug (const char *logPath = NULL, bool logInFile = true, bool eraseLastLog = false);
00092
00094 void destroyDebug();
00095
00096
00097 void changeLogDirectory(const std::string &dir);
00098
00099
00100 void enterBreakpoint (const char *message);
00101
00102
00103
00104 void setAssert (bool assert);
00105
00106
00107 void beep( uint freq, uint duration );
00108
00109
00110 typedef std::string (*TCrashCallback)();
00111
00112
00113 void setCrashCallback(TCrashCallback crashCallback);
00114
00115
00116 bool isCrashAlreadyReported();
00117 void setCrashAlreadyReported(bool state);
00118
00119
00120
00121 #ifdef NL_COMP_VC6
00122 # define __FUNCTION__ NULL
00123 #endif
00124
00125
00126
00127
00129 #define NL_MACRO_TO_STR_SUBPART(x) #x
00130
00139 #define NL_MACRO_TO_STR(x) NL_MACRO_TO_STR_SUBPART(x)
00140
00158 #define NL_LOC_MSG __FILE__"("NL_MACRO_TO_STR(__LINE__)") : Message: "
00159 #define NL_LOC_WRN __FILE__"("NL_MACRO_TO_STR(__LINE__)") : Warning Msg: "
00160
00161
00175 #ifdef NL_NO_DEBUG
00176 # if defined(NL_COMP_VC71) || defined(NL_COMP_VC8) || defined(NL_COMP_VC9)
00177 # define nldebug __noop
00178 # else
00179 # define nldebug 0&&
00180 # endif
00181 #else // NL_NO_DEBUG
00182 extern bool DisableNLDebug;
00183 # define nldebug if (NLMISC::DisableNLDebug) {} else (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getDebugLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getDebugLog())->displayNL
00184 #endif // NL_NO_DEBUG
00185
00190 #ifdef NL_NO_DEBUG
00191 # if defined(NL_COMP_VC71) || defined(NL_COMP_VC8) || defined(NL_COMP_VC9)
00192 # define nlinfo __noop
00193 # else
00194 # define nlinfo 0&&
00195 # endif
00196 #else // NL_NO_DEBUG
00197 # define nlinfo (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getInfoLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getInfoLog())->displayNL
00198 #endif // NL_NO_DEBUG
00199
00218 #ifdef NL_NO_DEBUG
00219 # if defined(NL_COMP_VC71) || defined(NL_COMP_VC8) || defined(NL_COMP_VC9)
00220 # define nlwarning __noop
00221 # else
00222 # define nlwarning 0&&
00223 # endif
00224 #else // NL_NO_DEBUG
00225 # define nlwarning (NLMISC::createDebug(), NLMISC::INelContext::getInstance().getWarningLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::INelContext::getInstance().getWarningLog())->displayNL
00226 #endif // NL_NO_DEBUG
00227
00244 #define nlerror (NLMISC::createDebug (), NLMISC::INelContext::getInstance().getErrorLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::nlFatalError)
00245
00246
00252 #define nlerrornoex (NLMISC::createDebug (), NLMISC::INelContext::getInstance().getErrorLog()->setPosition( __LINE__, __FILE__, __FUNCTION__ ), NLMISC::nlError)
00253
00254
00356
00357 #if defined (NL_OS_WINDOWS)
00358 #define NLMISC_BREAKPOINT __debugbreak();
00359 #else
00360 #define NLMISC_BREAKPOINT abort()
00361 #endif
00362
00363
00364 extern bool _assert_stop(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp);
00365 extern void _assertex_stop_0(bool &ignoreNextTime, sint line, const char *file, const char *funcName, const char *exp);
00366 extern bool _assertex_stop_1(bool &ignoreNextTime);
00367
00368
00369
00370 #ifdef NL_NO_DEBUG
00371 # define nlassert(exp) if(false)
00372 # define nlassertonce(exp) if(false)
00373 # define nlassertex(exp, str) if(false)
00374 # define nlverify(exp) { exp; }
00375 # define nlverifyonce(exp) { exp; }
00376 # define nlverifyex(exp, str) { exp; }
00377 #else // NL_NO_DEBUG
00378
00379 # ifdef NL_OS_UNIX
00380
00381
00382
00383 #define nlassert(exp) \
00384 { \
00385 if (!(exp)) { \
00386 NLMISC::createDebug (); \
00387 NLMISC::INelContext::getInstance().getAssertLog()->setPosition (__LINE__, __FILE__, __FUNCTION__); \
00388 NLMISC::INelContext::getInstance().getAssertLog()->displayNL ("\"%s\" ", #exp); \
00389 NLMISC_BREAKPOINT; \
00390 } \
00391 }
00392
00393 #define nlassertonce(exp) nlassert(exp)
00394
00395 #define nlassertex(exp, str) \
00396 { \
00397 if (!(exp)) { \
00398 NLMISC::createDebug (); \
00399 NLMISC::INelContext::getInstance().getAssertLog()->setPosition (__LINE__, __FILE__, __FUNCTION__); \
00400 NLMISC::INelContext::getInstance().getAssertLog()->displayNL ("\"%s\" ", #exp); \
00401 NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \
00402 NLMISC_BREAKPOINT; \
00403 } \
00404 }
00405
00406 #define nlverify(exp) nlassert(exp)
00407 #define nlverifyonce(exp) nlassert(exp)
00408 #define nlverifyex(exp, str) nlassertex(exp, str)
00409
00410 # else // NL_OS_UNIX
00411
00412 #define nlassert(exp) \
00413 { \
00414 static bool ignoreNextTime = false; \
00415 bool _expResult_ = (exp) ? true : false; \
00416 if (!ignoreNextTime && !_expResult_) { \
00417 if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \
00418 NLMISC_BREAKPOINT; \
00419 } \
00420 ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \
00421 }
00422
00423 #define nlassertonce(exp) \
00424 { \
00425 static bool ignoreNextTime = false; \
00426 if (!ignoreNextTime && !(exp)) { \
00427 ignoreNextTime = true; \
00428 if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \
00429 NLMISC_BREAKPOINT; \
00430 } \
00431 }
00432
00433 #define nlassertex(exp, str) \
00434 { \
00435 static bool ignoreNextTime = false; \
00436 bool _expResult_ = (exp) ? true : false; \
00437 if (!ignoreNextTime && !_expResult_) { \
00438 NLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp); \
00439 NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \
00440 if(NLMISC::_assertex_stop_1(ignoreNextTime)) \
00441 NLMISC_BREAKPOINT; \
00442 } \
00443 ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \
00444 }
00445
00446 #define nlverify(exp) \
00447 { \
00448 static bool ignoreNextTime = false; \
00449 bool _expResult_ = (exp) ? true : false; \
00450 if (!_expResult_ && !ignoreNextTime) { \
00451 if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \
00452 NLMISC_BREAKPOINT; \
00453 } \
00454 ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \
00455 }
00456
00457 #define nlverifyonce(exp) \
00458 { \
00459 static bool ignoreNextTime = false; \
00460 bool _expResult_ = (exp) ? true : false; \
00461 if (!_expResult_ && !ignoreNextTime) { \
00462 ignoreNextTime = true; \
00463 if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp)) \
00464 NLMISC_BREAKPOINT; \
00465 } \
00466 }
00467
00468 #define nlverifyex(exp, str) \
00469 { \
00470 static bool ignoreNextTime = false; \
00471 bool _expResult_ = (exp) ? true : false; \
00472 if (!_expResult_ && !ignoreNextTime) { \
00473 NLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, #exp); \
00474 NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \
00475 if(NLMISC::_assertex_stop_1(ignoreNextTime)) \
00476 NLMISC_BREAKPOINT; \
00477 } \
00478 ASSERT_THROW_EXCEPTION_CODE_EX(_expResult_, #exp) \
00479 }
00480
00481 # endif // NL_OS_UNIX
00482
00483 #endif // NL_NO_DEBUG
00484
00485 #define nlunreferenced(identifier) (identifier)
00486
00487 #define nlstop \
00488 { \
00489 static bool ignoreNextTime = false; \
00490 if (!ignoreNextTime) { \
00491 if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL)) \
00492 NLMISC_BREAKPOINT; \
00493 } \
00494 ASSERT_THROW_EXCEPTION_CODE(false) \
00495 }
00496
00497 #define nlstoponce \
00498 { \
00499 static bool ignoreNextTime = false; \
00500 if (!ignoreNextTime) { \
00501 ignoreNextTime = true; \
00502 if(NLMISC::_assert_stop(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL)) \
00503 NLMISC_BREAKPOINT; \
00504 } \
00505 }
00506
00507
00508 #define nlstopex(str) \
00509 { \
00510 static bool ignoreNextTime = false; \
00511 if (!ignoreNextTime) { \
00512 NLMISC::_assertex_stop_0(ignoreNextTime, __LINE__, __FILE__, __FUNCTION__, NULL); \
00513 NLMISC::INelContext::getInstance().getAssertLog()->displayRawNL str; \
00514 if(NLMISC::_assertex_stop_1(ignoreNextTime)) \
00515 NLMISC_BREAKPOINT; \
00516 } \
00517 }
00518
00519
00520 struct EFatalError : public Exception
00521 {
00522 EFatalError() : Exception( "nlerror() called" ) {}
00523 };
00524
00525 class ETrapDebug : public Exception
00526 {
00527 };
00528
00529
00530
00531
00532
00533 #ifdef NL_MAP_ASSERT
00534 # ifdef assert
00535 # undef assert
00536 # define assert nlassert
00537 # endif
00538 #else
00539 # ifdef assert
00540 # undef assert
00541 # define assert(a) you_must_not_use_assert___use_nl_assert___read_debug_h_file
00542 # endif
00543 #endif
00544
00545
00547 void getCallStack(std::string &result, sint skipNFirst = 0);
00548
00550 void getCallStackAndLog (std::string &result, sint skipNFirst = 0);
00551
00556 template<class T, class U> inline T safe_cast(U o)
00557 {
00558
00559 #ifdef NL_DEBUG
00560 nlassert(dynamic_cast<T>(o));
00561 #endif
00562 return static_cast<T>(o);
00563 }
00564
00570 template<class T, class U> inline T type_cast(U o)
00571 {
00572
00573 #ifdef NL_DEBUG
00574 if (o)
00575 nlassert(dynamic_cast<T>(o));
00576 #endif
00577
00578 if ((size_t)(static_cast<T>((U)0x0400)) == (size_t)((U)0x0400))
00579 {
00580 return static_cast<T>(o);
00581 }
00582 else
00583 {
00584 return (o==0)?0:static_cast<T>(o);
00585 }
00586 }
00587
00590 #define nlctassert(cond) sizeof(uint[(cond) ? 1 : 0])
00591
00610
00611 extern bool DebugNeedAssert;
00612
00613
00614 extern bool NoAssert;
00615
00616
00617 template<class T>
00618 class CMustConsume
00619 {
00620 public:
00621 CMustConsume(const T &val) : Value(val)
00622 #if !FINAL_VERSION
00623 , Consumed(false)
00624 #endif
00625 {
00626 }
00627
00628 ~CMustConsume()
00629 {
00630 #if !FINAL_VERSION
00631 nlassert(Consumed == true);
00632 #endif
00633 }
00634
00635
00636 const T &value() const
00637 {
00638 return Value;
00639 }
00640
00641 operator const T &() const
00642 {
00643 #if !FINAL_VERSION
00644 Consumed = true;
00645 #endif
00646 return Value;
00647 }
00648
00649
00650 const T &consumeValue() const
00651 {
00652 #if !FINAL_VERSION
00653 Consumed = true;
00654 #endif
00655 return Value;
00656 }
00657
00658 void consume() const
00659 {
00660 #if !FINAL_VERSION
00661 Consumed = true;
00662 #endif
00663 }
00664
00665 private:
00666 T Value;
00667 #if !FINAL_VERSION
00668 mutable bool Consumed;
00669 #endif
00670 };
00671
00673 struct TInstanceCounterData
00674 {
00675 sint32 _InstanceCounter;
00676 sint32 _DeltaCounter;
00677 const char *_ClassName;
00678 bool _Touched;
00679
00680 TInstanceCounterData(const char *className);
00681
00682 ~TInstanceCounterData();
00683 };
00684
00685
00686 class CInstanceCounterLocalManager;
00687
00688
00689 class CInstanceCounterManager
00690 {
00691
00692 private:
00693
00694 CInstanceCounterManager () {}
00695 CInstanceCounterManager (const CInstanceCounterManager &) {}
00696
00697 static CInstanceCounterManager *_Instance;
00698 public:
00699 static CInstanceCounterManager &getInstance()
00700 {
00701 if (_Instance == NULL)
00702 {
00703
00704
00705 void *ptr = NLMISC::INelContext::getInstance().getSingletonPointer("CInstanceCounterManager");
00706 if (ptr == NULL)
00707 {
00708
00709 _Instance = new CInstanceCounterManager;
00710 NLMISC::INelContext::getInstance().setSingletonPointer("CInstanceCounterManager", _Instance);
00711 }
00712 else
00713 {
00714 _Instance = reinterpret_cast<CInstanceCounterManager*>(ptr);
00715 }
00716 }
00717 return *_Instance;
00718 }
00719 private:
00720 public:
00721
00722 std::string displayCounters() const;
00723
00724 void resetDeltaCounter();
00725
00726 uint32 getInstanceCounter(const std::string &className) const;
00727 sint32 getInstanceCounterDelta(const std::string &className) const;
00728
00729 private:
00730
00731 friend class CInstanceCounterLocalManager;
00732
00733 void registerInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr);
00734 void unregisterInstaceCounterLocalManager(CInstanceCounterLocalManager *localMgr);
00735
00736
00737 std::set<CInstanceCounterLocalManager*> _InstanceCounterMgrs;
00738 };
00739
00740
00741
00742
00743 class CInstanceCounterLocalManager
00744 {
00745 public:
00746 static CInstanceCounterLocalManager &getInstance()
00747 {
00748 if (_Instance == NULL)
00749 {
00750 _Instance = new CInstanceCounterLocalManager;
00751 }
00752 return *_Instance;
00753 }
00754
00755 static void releaseInstance()
00756 {
00757 if (_Instance != NULL)
00758 {
00759 delete _Instance;
00760 _Instance = NULL;
00761 }
00762 }
00763
00764 void registerInstanceCounter(TInstanceCounterData *counter)
00765 {
00766 _InstanceCounters.insert(counter);
00767 }
00768
00769 void unregisterInstanceCounter(TInstanceCounterData *counter);
00770
00771 ~CInstanceCounterLocalManager()
00772 {
00773 CInstanceCounterManager::getInstance().unregisterInstaceCounterLocalManager(this);
00774 }
00775
00776 private:
00777 friend class CInstanceCounterManager;
00778 friend class INelContext;
00779
00780 CInstanceCounterLocalManager()
00781 {
00782 }
00783
00784 void registerLocalManager()
00785 {
00786 CInstanceCounterManager::getInstance().registerInstaceCounterLocalManager(this);
00787 }
00788
00789 static CInstanceCounterLocalManager *_Instance;
00790 std::set<TInstanceCounterData*> _InstanceCounters;
00791 };
00792
00793
00816 #define NL_INSTANCE_COUNTER_DECL(className) \
00817 public: \
00818 struct className##InstanceCounter \
00819 { \
00820 className##InstanceCounter() \
00821 { \
00822 _InstanceCounterData._InstanceCounter++; \
00823 _InstanceCounterData._Touched = true; \
00824 } \
00825 className##InstanceCounter(const className##InstanceCounter &) \
00826 { \
00827 _InstanceCounterData._InstanceCounter++; \
00828 _InstanceCounterData._Touched = true; \
00829 } \
00830 \
00831 ~className##InstanceCounter()\
00832 { \
00833 _InstanceCounterData._InstanceCounter--; \
00834 } \
00835 static sint32 getInstanceCounter() \
00836 { \
00837 return _InstanceCounterData._InstanceCounter; \
00838 } \
00839 static sint32 getInstanceCounterDelta() \
00840 { \
00841 return _InstanceCounterData._InstanceCounter - _InstanceCounterData._DeltaCounter; \
00842 } \
00843 static NLMISC::TInstanceCounterData _InstanceCounterData; \
00844 }; \
00845 \
00846 className##InstanceCounter _##className##InstanceCounter; \
00847 private:
00848
00850 #define NL_INSTANCE_COUNTER_IMPL(className) NLMISC::TInstanceCounterData className::className##InstanceCounter::_InstanceCounterData(#className);
00851
00853 #define NL_GET_LOCAL_INSTANCE_COUNTER(className) className::className##InstanceCounter::getInstanceCounter()
00854 #define NL_GET_INSTANCE_COUNTER(className) NLMISC::CInstanceCounterManager::getInstance().getInstanceCounter(#className)
00855
00857 #define NL_GET_LOCAL_INSTANCE_COUNTER_DELTA(className) className::className##InstanceCounter::getInstanceCounterDelta()
00858 #define NL_GET_INSTANCE_COUNTER_DELTA(className) NLMISC::CInstanceCounterManager::getInstance().getInstanceCounterDelta(#className)
00859
00860
00861
00862
00863
00865 void nlFatalError (const char *format, ...);
00866
00868 void nlError (const char *format, ...);
00869
00870 #define NL_CRASH_DUMP_FILE "nel_debug.dmp"
00871
00872
00873
00875 int getLastError();
00876
00878 std::string formatErrorMessage(int errorCode);
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907
00908 class CNLDebugOverride
00909 {
00910 public:
00911 CNLDebugOverride(NLMISC::CLog *debugLog)
00912 {
00913 nlassert(debugLog!=NULL);
00914 _OldValue=NLMISC::DebugLog;
00915 nlassert(_OldValue!=NULL);
00916 NLMISC::INelContext::getInstance().setDebugLog(debugLog);
00917 }
00918 ~CNLDebugOverride()
00919 {
00920 NLMISC::INelContext::getInstance().setDebugLog(_OldValue);
00921 }
00922 private:
00923
00924 CNLDebugOverride(const CNLDebugOverride&);
00925 NLMISC::CLog *_OldValue;
00926 };
00927
00928
00929
00930 class CNLInfoOverride
00931 {
00932 public:
00933 CNLInfoOverride(NLMISC::CLog *infoLog)
00934 {
00935 nlassert(infoLog!=NULL);
00936 _OldValue=NLMISC::InfoLog;
00937 nlassert(_OldValue!=NULL);
00938 NLMISC::INelContext::getInstance().setInfoLog(infoLog);
00939 }
00940 ~CNLInfoOverride()
00941 {
00942 NLMISC::INelContext::getInstance().setInfoLog(_OldValue);
00943 }
00944 private:
00945
00946 CNLInfoOverride(const CNLInfoOverride&);
00947 NLMISC::CLog *_OldValue;
00948 };
00949
00950
00951
00952 class CNLWarningOverride
00953 {
00954 public:
00955 CNLWarningOverride(NLMISC::CLog *warningLog)
00956 {
00957 nlassert(warningLog!=NULL);
00958 _OldValue=NLMISC::WarningLog;
00959 nlassert(_OldValue!=NULL);
00960 NLMISC::INelContext::getInstance().setWarningLog(warningLog);
00961 }
00962 ~CNLWarningOverride()
00963 {
00964 NLMISC::INelContext::getInstance().setWarningLog(_OldValue);
00965 }
00966 private:
00967
00968 CNLWarningOverride(const CNLWarningOverride&);
00969 NLMISC::CLog *_OldValue;
00970 };
00971
00972
00973
00974 class CNLLogOverride
00975 {
00976 public:
00977 CNLLogOverride(NLMISC::CLog *commonLog): _DebugLog(commonLog), _InfoLog(commonLog), _WarningLog(commonLog) {}
00978
00979 private:
00980 CNLDebugOverride _DebugLog;
00981 CNLInfoOverride _InfoLog;
00982 CNLWarningOverride _WarningLog;
00983 };
00984
00985
00986
00987
00988 class CNLSmartLogOverride
00989 {
00990 public:
00991 CNLSmartLogOverride(NLMISC::CLog *commonLog):
00992 _DebugLog(commonLog==NLMISC::InfoLog?NLMISC::DebugLog:commonLog),
00993 _InfoLog(commonLog),
00994 _WarningLog(commonLog==NLMISC::InfoLog?NLMISC::WarningLog:commonLog)
00995 {}
00996
00997 private:
00998 CNLDebugOverride _DebugLog;
00999 CNLInfoOverride _InfoLog;
01000 CNLWarningOverride _WarningLog;
01001 };
01002
01003
01004
01005
01006 }
01007
01008 #endif // NL_DEBUG_H
01009
01010