#ifndef __DEBUG_H__ #define __DEBUG_H__ // Abstract: This file provides the following macros: // // ASSERT(p) - If p is false and DEBUG is true drops into the // debugger, if ASSERTS_THROW is true throws a XAssertException exception. // // VERIFY(p) - Like ASSERT except that p is evaluated in release builds. // // REQUIRE(p) - Like VERIFY except that it exits the app if the test fails // (this is needed because the boot strap code can't safely throw). // // COMPILE_CHECK(p) - An ASSERT that fires at compile time. This is useful // for doing things like verifying the layout of items within a struct. // Note that this check is also done in release builds. // // DEBUGSTR(formatStr, n1, n2, ...) - Drops into the debugger and // displays a string. // // TRACE(formatStr, n1, n2, ...) - Writes a string to a debug window // without suspending the program. // // TRACEFLOW(category, formatStr, n1, n2, ...) - Like TRACE, but with // the addition of a category string. The category string allows users // to turn off entire categories of messages. Note that DEBUGSTR, TRACE, // and TRACEFLOW may be used with boolean expressions by tacking an _IF // on the end (eg DEBUGSTR_IF(x < 0, "Sqrt was passed a negative argument.")). // // PRECONDITION(p) - Used in conjunction with POSTCONDITION to verify // the integrity of an object: each public method should include one call to // PRECONDITION and another to POSTCONDITION. The idea here is to check to // see if the object stays in a valid state given valid arguments. Note that // these macros call a method named Invariant. This method should use ASSERT's // to check to see if the object is in a sane state. See ZInvariant.h for // more details. // // CHECK_INVARIANT() - Calls the Invariant. This is useful in ctors because // PRECONDITION doesn't call the dtor (PRECONDITION constructs an object on // the stack which calls the Invariant when the function exits). #pragma once // Open only once per build #define RUNTIME_EXPORT RUNTIME_EXPORT std::wstring ToStr(bool value); // I originally used iostreams, but that caused a ridiculous amount of bloat in object files (but much less so in the exe) RUNTIME_EXPORT std::wstring ToStr(char value); inline std::wstring ToStr(wchar_t value) {return std::wstring(1, value);} RUNTIME_EXPORT std::wstring ToStr(int16_t value, int32_t fieldWidth = 1); RUNTIME_EXPORT std::wstring ToStr(uint16_t value, int32_t fieldWidth = 1); RUNTIME_EXPORT std::wstring ToStr(int32_t value, int32_t fieldWidth = 1); RUNTIME_EXPORT std::wstring ToStr(uint32_t value, int32_t fieldWidth = 1); RUNTIME_EXPORT std::wstring ToStr(float value, int32_t precision = 6); RUNTIME_EXPORT std::wstring ToStr(double_t value, int32_t precision = 6); RUNTIME_EXPORT std::wstring ToStr(const char* value); inline std::wstring ToStr(const wchar_t* value) {return value;} RUNTIME_EXPORT std::wstring ToStr(const std::string& value); inline std::wstring ToStr(const std::wstring& value) {return value;} #ifdef _DEBUG #define DEBUG 1 #else #define DEBUG 0 #if !defined(NDEBUG) #define NDEBUG // used by #endif #endif #ifndef ASSERTS_THROW #define ASSERTS_THROW 0 #endif // #define ASSERTS_THROW 1 // Synch with ANSI definitions. #if DEBUG && defined(NDEBUG) #error DEBUG and NDEBUG are out of sync! #endif #if !DEBUG && !defined(NDEBUG) #error DEBUG and NDEBUG are out of sync! #endif // Synch with MSVC. #if _MSC_VER && DEBUG != defined(_DEBUG) #error DEBUG and _DEBUG are out of sync! #endif #ifndef _lint #define COMPILE_CHECK(p) {struct _CC {char a[(p) ? 1 : -1];};} (void) 0 #else #define COMPILE_CHECK(p) #endif #if DEBUG void AssertFailed(const char* expr, const char* file, int line); #undef assert #define ASSERT(p) do {if (!(p)) AssertFailed(#p, __FILE__, __LINE__);} while (false) #define ASSERT_IF(p, x) do {if ((p) && !(x)) AssertFailed(#x, __FILE__, __LINE__);} while (false) #define assert(p) ASSERT(p) #define VERIFY(p) ASSERT(p) #define REQUIRE(p) ASSERT(p) #define PRECONDITION(p) ASSERT(p) #define POSTCONDITION(p) ASSERT(p) #ifdef NO_NESTED_QUOTES #define PRECONDITION2(a,b) ASSERT(a) #define POSTCONDITION2(a,b) ASSERT(a) #else #define PRECONDITION2(a,b) ASSERT((b, (a) !=0)) #define POSTCONDITION2(a,b) ASSERT((b, (a) !=0)) #endif #else // #if DEBUG #if ASSERTS_THROW void AssertFailed(const char*, const char*, int); #define ASSERT(p) do {if (!(p)) AssertFailed(#p, __FILE__, __LINE__);} while (false) #define ASSERT_IF(p, x) do {if ((p) && !(x)) AssertFailed(#x, __FILE__, __LINE__);} while (false) #define VERIFY(p) ASSERT(p) #define PRECONDITION(p) ASSERT(p) #define POSTCONDITION(p) ASSERT(p) #define PRECONDITION2(a,b) ASSERT(a) #define POSTCONDITION2(a,b) ASSERT(a) #else #define ASSERT(p) ((void) 0) #define ASSERT_IF(p, x) ((void) 0) #define VERIFY(p) do {if (p) 0;} while (false) #define PRECONDITION(p) ((void) 0) #define POSTCONDITION(p) ((void) 0) #define PRECONDITION2(a,b) #define POSTCONDITION2(a,b) #endif void RequireFailed(const char*, const char*, int); #define REQUIRE(p) do {if (!(p)) RequireFailed(#p, __FILE__, __LINE__);} while (false) #endif // DEBUG #ifdef _CONSOLE #define TRACE #endif #endif /* __DEBUG_H__ */