Merge changes from the Witness.
This commit is contained in:
@ -108,7 +108,7 @@ namespace nv
|
||||
|
||||
void push_back( const T & val );
|
||||
void pushBack( const T & val );
|
||||
void append( const T & val );
|
||||
Array<T> & append( const T & val );
|
||||
Array<T> & operator<< ( T & t );
|
||||
void pop_back();
|
||||
void popBack();
|
||||
@ -160,7 +160,7 @@ namespace nv
|
||||
friend void swap(Array<Typ> & a, Array<Typ> & b);
|
||||
|
||||
|
||||
protected:
|
||||
protected:
|
||||
|
||||
void setArraySize(uint new_size);
|
||||
void setArrayCapacity(uint new_capacity);
|
||||
|
@ -22,7 +22,7 @@ namespace nv
|
||||
NV_FORCEINLINE void Array<T>::push_back( const T & val )
|
||||
{
|
||||
#if 1
|
||||
nvDebugCheck(&val < m_buffer || &val > m_buffer+m_size);
|
||||
nvDebugCheck(&val < m_buffer || &val >= m_buffer+m_size);
|
||||
|
||||
uint old_size = m_size;
|
||||
uint new_size = m_size + 1;
|
||||
@ -57,9 +57,10 @@ namespace nv
|
||||
push_back(val);
|
||||
}
|
||||
template <typename T>
|
||||
NV_FORCEINLINE void Array<T>::append( const T & val )
|
||||
NV_FORCEINLINE Array<T> & Array<T>::append( const T & val )
|
||||
{
|
||||
push_back(val);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Qt like push operator.
|
||||
|
@ -66,7 +66,7 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define USE_SEPARATE_THREAD 1
|
||||
#define NV_USE_SEPARATE_THREAD 1
|
||||
|
||||
|
||||
using namespace nv;
|
||||
@ -101,7 +101,7 @@ namespace
|
||||
// We should try to simplify the top level filter as much as possible.
|
||||
// http://www.nynaeve.net/?p=128
|
||||
|
||||
#if USE_SEPARATE_THREAD
|
||||
#if NV_USE_SEPARATE_THREAD
|
||||
|
||||
// The critical section enforcing the requirement that only one exception be
|
||||
// handled by a handler at a time.
|
||||
@ -121,7 +121,7 @@ namespace
|
||||
static DWORD s_requesting_thread_id = 0;
|
||||
static EXCEPTION_POINTERS * s_exception_info = NULL;
|
||||
|
||||
#endif // USE_SEPARATE_THREAD
|
||||
#endif // NV_USE_SEPARATE_THREAD
|
||||
|
||||
|
||||
struct MinidumpCallbackContext {
|
||||
@ -236,7 +236,7 @@ namespace
|
||||
return true;
|
||||
}
|
||||
|
||||
#if USE_SEPARATE_THREAD
|
||||
#if NV_USE_SEPARATE_THREAD
|
||||
|
||||
static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter) {
|
||||
nvDebugCheck(s_handler_start_semaphore != NULL);
|
||||
@ -256,7 +256,7 @@ namespace
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // USE_SEPARATE_THREAD
|
||||
#endif // NV_USE_SEPARATE_THREAD
|
||||
|
||||
static bool hasStackTrace() {
|
||||
return true;
|
||||
@ -387,7 +387,9 @@ namespace
|
||||
DWORD dwDisplacement;
|
||||
if (!SymGetLineFromAddr64(hProcess, ip, &dwDisplacement, &theLine))
|
||||
{
|
||||
builder.format("unknown(%08X) : %s\n", (uint32)ip, pFunc);
|
||||
// Do not print unknown symbols anymore.
|
||||
break;
|
||||
//builder.format("unknown(%08X) : %s\n", (uint32)ip, pFunc);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -404,6 +406,10 @@ namespace
|
||||
}
|
||||
|
||||
lines.append(builder.release());
|
||||
|
||||
if (pFunc != NULL && strcmp(pFunc, "WinMain") == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -413,7 +419,7 @@ namespace
|
||||
static LONG WINAPI handleException(EXCEPTION_POINTERS * pExceptionInfo)
|
||||
{
|
||||
EnterCriticalSection(&s_handler_critical_section);
|
||||
#if USE_SEPARATE_THREAD
|
||||
#if NV_USE_SEPARATE_THREAD
|
||||
s_requesting_thread_id = GetCurrentThreadId();
|
||||
s_exception_info = pExceptionInfo;
|
||||
|
||||
@ -474,6 +480,36 @@ namespace
|
||||
}
|
||||
|
||||
static void handleInvalidParameter(const wchar_t * expresion, const wchar_t * function, const wchar_t * file, unsigned int line, uintptr_t reserved) {
|
||||
|
||||
size_t convertedCharCount = 0;
|
||||
StringBuilder tmp;
|
||||
|
||||
if (expresion != NULL) {
|
||||
uint size = toU32(wcslen(expresion) + 1);
|
||||
tmp.reserve(size);
|
||||
wcstombs_s(&convertedCharCount, tmp.str(), size, expresion, _TRUNCATE);
|
||||
|
||||
nvDebug("*** Invalid parameter: %s\n", tmp.str());
|
||||
|
||||
if (file != NULL) {
|
||||
size = toU32(wcslen(file) + 1);
|
||||
tmp.reserve(size);
|
||||
wcstombs_s(&convertedCharCount, tmp.str(), size, file, _TRUNCATE);
|
||||
|
||||
nvDebug(" On file: %s\n", tmp.str());
|
||||
|
||||
if (function != NULL) {
|
||||
size = toU32(wcslen(function) + 1);
|
||||
tmp.reserve(size);
|
||||
wcstombs_s(&convertedCharCount, tmp.str(), size, function, _TRUNCATE);
|
||||
|
||||
nvDebug(" On function: %s\n", tmp.str());
|
||||
}
|
||||
|
||||
nvDebug(" On line: %u\n", line);
|
||||
}
|
||||
}
|
||||
|
||||
nvDebugBreak();
|
||||
TerminateProcess(GetCurrentProcess(), EXIT_FAILURE + 8);
|
||||
}
|
||||
@ -706,16 +742,22 @@ namespace
|
||||
}
|
||||
|
||||
// Assert handler method.
|
||||
virtual int assertion( const char * exp, const char * file, int line, const char * func/*=NULL*/ )
|
||||
virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
|
||||
{
|
||||
int ret = NV_ABORT_EXIT;
|
||||
|
||||
StringBuilder error_string;
|
||||
if( func != NULL ) {
|
||||
error_string.format( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
|
||||
error_string.format("*** Assertion failed: %s\n On file: %s\n On line: %d\n", exp, file, line );
|
||||
if (func != NULL) {
|
||||
error_string.appendFormat(" On function: %s\n", func);
|
||||
}
|
||||
else {
|
||||
error_string.format( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
|
||||
if (msg != NULL) {
|
||||
error_string.append(" Message: ");
|
||||
va_list tmp;
|
||||
va_copy(tmp, arg);
|
||||
error_string.appendFormatList(msg, tmp);
|
||||
va_end(tmp);
|
||||
error_string.append("\n");
|
||||
}
|
||||
nvDebug( error_string.str() );
|
||||
|
||||
@ -760,7 +802,7 @@ namespace
|
||||
struct Xbox360AssertHandler : public AssertHandler
|
||||
{
|
||||
// Assert handler method.
|
||||
virtual int assertion( const char * exp, const char * file, int line, const char * func/*=NULL*/ )
|
||||
virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
|
||||
{
|
||||
int ret = NV_ABORT_EXIT;
|
||||
|
||||
@ -786,14 +828,47 @@ namespace
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
#elif NV_OS_ORBIS
|
||||
|
||||
/** Orbis assert handler. */
|
||||
struct OrbisAssertHandler : public AssertHandler
|
||||
{
|
||||
// Assert handler method.
|
||||
virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
|
||||
{
|
||||
if( func != NULL ) {
|
||||
nvDebug( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
|
||||
}
|
||||
else {
|
||||
nvDebug( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
|
||||
}
|
||||
|
||||
//SBtodoORBIS print stack trace
|
||||
/*if (hasStackTrace())
|
||||
{
|
||||
void * trace[64];
|
||||
int size = backtrace(trace, 64);
|
||||
printStackTrace(trace, size, 2);
|
||||
}*/
|
||||
|
||||
//SBtodoORBIS check for debugger present
|
||||
//if (debug::isDebuggerPresent())
|
||||
nvDebugBreak();
|
||||
|
||||
return NV_ABORT_DEBUG;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
/** Unix assert handler. */
|
||||
struct UnixAssertHandler : public AssertHandler
|
||||
{
|
||||
// Assert handler method.
|
||||
virtual int assertion(const char * exp, const char * file, int line, const char * func)
|
||||
virtual int assertion(const char * exp, const char * file, int line, const char * func, const char * msg, va_list arg)
|
||||
{
|
||||
int ret = NV_ABORT_EXIT;
|
||||
|
||||
if( func != NULL ) {
|
||||
nvDebug( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
|
||||
}
|
||||
@ -816,9 +891,13 @@ namespace
|
||||
}
|
||||
#endif
|
||||
|
||||
if( ret == NV_ABORT_EXIT ) {
|
||||
// Exit cleanly.
|
||||
exit(EXIT_FAILURE + 1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -827,22 +906,27 @@ namespace
|
||||
|
||||
|
||||
/// Handle assertion through the assert handler.
|
||||
int nvAbort(const char * exp, const char * file, int line, const char * func/*=NULL*/)
|
||||
int nvAbort(const char * exp, const char * file, int line, const char * func/*=NULL*/, const char * msg/*= NULL*/, ...)
|
||||
{
|
||||
#if NV_OS_WIN32 //&& NV_CC_MSVC
|
||||
static Win32AssertHandler s_default_assert_handler;
|
||||
#elif NV_OS_XBOX
|
||||
static Xbox360AssertHandler s_default_assert_handler;
|
||||
#elif NV_OS_ORBIS
|
||||
static OrbisAssertHandler s_default_assert_handler;
|
||||
#else
|
||||
static UnixAssertHandler s_default_assert_handler;
|
||||
#endif
|
||||
|
||||
if (s_assert_handler != NULL) {
|
||||
return s_assert_handler->assertion( exp, file, line, func );
|
||||
}
|
||||
else {
|
||||
return s_default_assert_handler.assertion( exp, file, line, func );
|
||||
}
|
||||
va_list arg;
|
||||
va_start(arg,msg);
|
||||
|
||||
AssertHandler * handler = s_assert_handler != NULL ? s_assert_handler : &s_default_assert_handler;
|
||||
int result = handler->assertion(exp, file, line, func, msg, arg);
|
||||
|
||||
va_end(arg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Abnormal termination. Create mini dump and output call stack.
|
||||
@ -914,6 +998,26 @@ void debug::dumpInfo()
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Dump callstack using the specified handler.
|
||||
void debug::dumpCallstack(MessageHandler *messageHandler, int callstackLevelsToSkip /*= 0*/)
|
||||
{
|
||||
#if (NV_OS_WIN32 && NV_CC_MSVC) || (defined(HAVE_SIGNAL_H) && defined(HAVE_EXECINFO_H))
|
||||
if (hasStackTrace())
|
||||
{
|
||||
void * trace[64];
|
||||
int size = backtrace(trace, 64);
|
||||
|
||||
Array<const char *> lines;
|
||||
writeStackTrace(trace, size, callstackLevelsToSkip + 1, lines); // + 1 to skip the call to dumpCallstack
|
||||
|
||||
for (uint i = 0; i < lines.count(); i++) {
|
||||
messageHandler->log(lines[i], NULL);
|
||||
delete lines[i];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// Set the debug message handler.
|
||||
void debug::setMessageHandler(MessageHandler * message_handler)
|
||||
@ -939,9 +1043,8 @@ void debug::resetAssertHandler()
|
||||
s_assert_handler = NULL;
|
||||
}
|
||||
|
||||
|
||||
#if NV_OS_WIN32
|
||||
#if USE_SEPARATE_THREAD
|
||||
#if NV_USE_SEPARATE_THREAD
|
||||
|
||||
static void initHandlerThread()
|
||||
{
|
||||
@ -984,7 +1087,7 @@ static void shutHandlerThread() {
|
||||
// @@ Free stuff. Terminate thread.
|
||||
}
|
||||
|
||||
#endif // USE_SEPARATE_THREAD
|
||||
#endif // NV_USE_SEPARATE_THREAD
|
||||
#endif // NV_OS_WIN32
|
||||
|
||||
|
||||
@ -1009,7 +1112,7 @@ void debug::enableSigHandler(bool interactive)
|
||||
}
|
||||
|
||||
|
||||
#if USE_SEPARATE_THREAD
|
||||
#if NV_USE_SEPARATE_THREAD
|
||||
initHandlerThread();
|
||||
#endif
|
||||
|
||||
|
@ -70,11 +70,12 @@
|
||||
} \
|
||||
NV_MULTI_LINE_MACRO_END
|
||||
|
||||
#define nvAssertMacroWithIgnoreAll(exp) \
|
||||
// GCC, LLVM need "##" before the __VA_ARGS__, MSVC doesn't care
|
||||
#define nvAssertMacroWithIgnoreAll(exp,...) \
|
||||
NV_MULTI_LINE_MACRO_BEGIN \
|
||||
static bool ignoreAll = false; \
|
||||
if (!ignoreAll && !(exp)) { \
|
||||
int result = nvAbort(#exp, __FILE__, __LINE__, __FUNC__); \
|
||||
int result = nvAbort(#exp, __FILE__, __LINE__, __FUNC__, ##__VA_ARGS__); \
|
||||
if (result == NV_ABORT_DEBUG) { \
|
||||
nvDebugBreak(); \
|
||||
} else if (result == NV_ABORT_IGNORE) { \
|
||||
@ -157,7 +158,7 @@
|
||||
#endif
|
||||
|
||||
|
||||
NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = NULL);
|
||||
NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = NULL, const char * msg = NULL, ...);
|
||||
NVCORE_API void NV_CDECL nvDebugPrint( const char *msg, ... ) __attribute__((format (printf, 1, 2)));
|
||||
|
||||
namespace nv
|
||||
@ -184,7 +185,7 @@ namespace nv
|
||||
|
||||
// Assert handler interface.
|
||||
struct AssertHandler {
|
||||
virtual int assertion(const char *exp, const char *file, int line, const char *func = NULL) = 0;
|
||||
virtual int assertion(const char *exp, const char *file, int line, const char *func, const char *msg, va_list arg) = 0;
|
||||
virtual ~AssertHandler() {}
|
||||
};
|
||||
|
||||
@ -192,6 +193,7 @@ namespace nv
|
||||
namespace debug
|
||||
{
|
||||
NVCORE_API void dumpInfo();
|
||||
NVCORE_API void dumpCallstack( MessageHandler *messageHandler, int callstackLevelsToSkip = 0 );
|
||||
|
||||
NVCORE_API void setMessageHandler( MessageHandler * messageHandler );
|
||||
NVCORE_API void resetMessageHandler();
|
||||
|
@ -27,6 +27,7 @@
|
||||
#define NV_FASTCALL __attribute__((fastcall))
|
||||
#define NV_FORCEINLINE __attribute__((always_inline)) inline
|
||||
#define NV_DEPRECATED __attribute__((deprecated))
|
||||
#define NV_THREAD_LOCAL //ACS: there's no "__thread" or equivalent on iOS/OSX
|
||||
|
||||
#if __GNUC__ > 2
|
||||
#define NV_PURE __attribute__((pure))
|
||||
@ -38,6 +39,8 @@
|
||||
|
||||
#define NV_NOINLINE __attribute__((noinline))
|
||||
|
||||
|
||||
|
||||
// Define __FUNC__ properly.
|
||||
#if __STDC_VERSION__ < 199901L
|
||||
# if __GNUC__ >= 2
|
||||
|
@ -25,8 +25,9 @@
|
||||
#endif
|
||||
|
||||
#define NV_FASTCALL __attribute__((fastcall))
|
||||
#define NV_FORCEINLINE inline __attribute__((always_inline))
|
||||
#define NV_FORCEINLINE __attribute__((always_inline))
|
||||
#define NV_DEPRECATED __attribute__((deprecated))
|
||||
#define NV_THREAD_LOCAL __thread
|
||||
|
||||
|
||||
#if __GNUC__ > 2
|
||||
|
@ -103,10 +103,25 @@ namespace nv
|
||||
clearerr(m_fp);
|
||||
}
|
||||
|
||||
// @@ The original implementation uses feof, which only returns true when we attempt to read *past* the end of the stream.
|
||||
// That is, if we read the last byte of a file, then isAtEnd would still return false, even though the stream pointer is at the file end. This is not the intent and was inconsistent with the implementation of the MemoryStream, a better
|
||||
// implementation uses use ftell and fseek to determine our location within the file.
|
||||
virtual bool isAtEnd() const
|
||||
{
|
||||
nvDebugCheck(m_fp != NULL);
|
||||
return feof( m_fp ) != 0;
|
||||
//return feof( m_fp ) != 0;
|
||||
#if NV_OS_WIN32
|
||||
uint pos = _ftell_nolock(m_fp);
|
||||
_fseek_nolock(m_fp, 0, SEEK_END);
|
||||
uint end = _ftell_nolock(m_fp);
|
||||
_fseek_nolock(m_fp, pos, SEEK_SET);
|
||||
#else
|
||||
uint pos = (uint)ftell(m_fp);
|
||||
fseek(m_fp, 0, SEEK_END);
|
||||
uint end = (uint)ftell(m_fp);
|
||||
fseek(m_fp, pos, SEEK_SET);
|
||||
#endif
|
||||
return pos == end;
|
||||
}
|
||||
|
||||
/// Always true.
|
||||
|
@ -101,6 +101,13 @@ bool nv::strEqual(const char * s1, const char * s2)
|
||||
return strCmp(s1, s2) == 0;
|
||||
}
|
||||
|
||||
bool nv::strCaseEqual(const char * s1, const char * s2)
|
||||
{
|
||||
if (s1 == s2) return true;
|
||||
if (s1 == NULL || s2 == NULL) return false;
|
||||
return strCaseCmp(s1, s2) == 0;
|
||||
}
|
||||
|
||||
bool nv::strBeginsWith(const char * str, const char * prefix)
|
||||
{
|
||||
//return strstr(str, prefix) == dst;
|
||||
@ -326,7 +333,7 @@ StringBuilder & StringBuilder::append( const char * s )
|
||||
if (m_str == NULL) {
|
||||
m_size = slen + 1;
|
||||
m_str = strAlloc(m_size);
|
||||
memcpy(m_str, s, m_size + 1);
|
||||
memcpy(m_str, s, m_size);
|
||||
}
|
||||
else {
|
||||
const uint len = uint(strlen( m_str ));
|
||||
|
@ -35,12 +35,12 @@ namespace nv
|
||||
uint operator()(const char * str) const { return strHash(str); }
|
||||
};
|
||||
|
||||
|
||||
NVCORE_API uint strLen(const char * str) NV_PURE;
|
||||
|
||||
NVCORE_API int strCaseCmp(const char * s1, const char * s2) NV_PURE;
|
||||
NVCORE_API int strCmp(const char * s1, const char * s2) NV_PURE;
|
||||
NVCORE_API int strCaseCmp(const char * s1, const char * s2) NV_PURE;
|
||||
NVCORE_API bool strEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings.
|
||||
NVCORE_API bool strCaseEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings.
|
||||
|
||||
template <> struct Equal<const char *> {
|
||||
bool operator()(const char * a, const char * b) const { return strEqual(a, b); }
|
||||
|
@ -23,7 +23,7 @@
|
||||
#define NV_INT32_MAX 2147483647
|
||||
#define NV_UINT32_MAX 0xffffffff
|
||||
#define NV_INT64_MAX POSH_I64(9223372036854775807)
|
||||
#define NV_INT64_MIN (-POSH_I64(9223372036854775808))
|
||||
#define NV_INT64_MIN (-POSH_I64(9223372036854775807)-1)
|
||||
#define NV_UINT64_MAX POSH_U64(0xffffffffffffffff)
|
||||
|
||||
#define NV_HALF_MAX 65504.0F
|
||||
|
@ -31,12 +31,16 @@
|
||||
// NV_OS_UNIX
|
||||
// NV_OS_DARWIN
|
||||
// NV_OS_XBOX
|
||||
// NV_OS_ORBIS
|
||||
// NV_OS_IOS
|
||||
|
||||
#define NV_OS_STRING POSH_OS_STRING
|
||||
|
||||
#if defined POSH_OS_LINUX
|
||||
# define NV_OS_LINUX 1
|
||||
# define NV_OS_UNIX 1
|
||||
#elif defined POSH_OS_ORBIS
|
||||
# define NV_OS_ORBIS 1
|
||||
#elif defined POSH_OS_FREEBSD
|
||||
# define NV_OS_FREEBSD 1
|
||||
# define NV_OS_UNIX 1
|
||||
@ -51,6 +55,10 @@
|
||||
#elif defined POSH_OS_OSX
|
||||
# define NV_OS_DARWIN 1
|
||||
# define NV_OS_UNIX 1
|
||||
#elif defined POSH_OS_IOS
|
||||
# define NV_OS_DARWIN 1 //ACS should we keep this on IOS?
|
||||
# define NV_OS_UNIX 1
|
||||
# define NV_OS_IOS 1
|
||||
#elif defined POSH_OS_UNIX
|
||||
# define NV_OS_UNIX 1
|
||||
#elif defined POSH_OS_WIN32
|
||||
@ -63,6 +71,22 @@
|
||||
# error "Unsupported OS"
|
||||
#endif
|
||||
|
||||
|
||||
// Threading:
|
||||
// some platforms don't implement __thread or similar for thread-local-storage
|
||||
#if NV_OS_UNIX || NV_OS_ORBIS || NV_OS_IOS //ACStodoIOS darwin instead of ios?
|
||||
# define NV_OS_USE_PTHREAD 1
|
||||
# if NV_OS_DARWIN || NV_OS_IOS
|
||||
# define NV_OS_HAS_TLS_QUALIFIER 0
|
||||
# else
|
||||
# define NV_OS_HAS_TLS_QUALIFIER 1
|
||||
# endif
|
||||
#else
|
||||
# define NV_OS_USE_PTHREAD 0
|
||||
# define NV_OS_HAS_TLS_QUALIFIER 1
|
||||
#endif
|
||||
|
||||
|
||||
// CPUs:
|
||||
// NV_CPU_X86
|
||||
// NV_CPU_X86_64
|
||||
@ -182,7 +206,7 @@ typedef uint32 uint;
|
||||
#endif
|
||||
|
||||
#if __cplusplus > 199711L
|
||||
#define nvStaticCheck(x) static_assert(x)
|
||||
#define nvStaticCheck(x) static_assert(x, "Static assert "#x" failed")
|
||||
#else
|
||||
#define nvStaticCheck(x) typedef char NV_STRING_JOIN2(__static_assert_,__LINE__)[(x)]
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user