diff --git a/src/nvcore/Array.h b/src/nvcore/Array.h index ae2b555..d3a7574 100644 --- a/src/nvcore/Array.h +++ b/src/nvcore/Array.h @@ -9,8 +9,8 @@ This array class requires the elements to be relocable; it uses memmove and real using swap, but I honestly don't care. The only thing that you should be aware of is that internal pointers are not supported. -The foreach macros that I use are very non-standard and somewhat confusing. It would be nice to have -standard foreach as in Qt. +Note also that push_back and resize does not support inserting arguments elements that are in the same +container. This is forbidden to prevent an extra copy. */ @@ -19,7 +19,7 @@ standard foreach as in Qt. #include "Debug.h" #include "Stream.h" #include "Utils.h" // swap -#include "ForEach.h" // swap +#include "ForEach.h" // PseudoIndex #include // memmove #include // for placement new @@ -27,69 +27,6 @@ standard foreach as in Qt. namespace nv { - // @@ Move this to utils? - /// Delete all the elements of a container. - template - void deleteAll(T & container) - { - for (typename T::PseudoIndex i = container.start(); !container.isDone(i); container.advance(i)) - { - delete container[i]; - } - } - - - // @@ Move these templates to Utils.h - // @@ Specialize these methods for numeric, pointer, and pod types. - - template - void construct_range(T * restrict ptr, uint new_size, uint old_size) { - for (uint i = old_size; i < new_size; i++) { - new(ptr+i) T; // placement new - } - } - - template - void construct_range(T * restrict ptr, uint new_size, uint old_size, const T & elem) { - for (uint i = old_size; i < new_size; i++) { - new(ptr+i) T(elem); // placement new - } - } - - template - void destroy_range(T * restrict ptr, uint new_size, uint old_size) { - for (uint i = new_size; i < old_size; i++) { - (ptr+i)->~T(); // Explicit call to the destructor - } - } - - template - void fill(T * restrict dst, uint count, const T & value) { - for (uint i = 0; i < count; i++) { - dst[i] = value; - } - } - - template - void copy(T * restrict dst, const T * restrict src, uint count) { - for (uint i = 0; i < count; i++) { - dst[i] = src[i]; - } - } - - template - bool find(const T & element, const T * restrict ptr, uint begin, uint end, uint * index) { - for (uint i = begin; i < end; i++) { - if (ptr[i] == element) { - if (index != NULL) *index = i; - return true; - } - } - return false; - } - - - /** * Replacement for std::vector that is easier to debug and provides * some nice foreach enumerators. @@ -107,7 +44,7 @@ namespace nv } // Constructor that initializes the vector with the given elements. - NV_FORCEINLINE Array(const T * ptr, int num) : m_buffer(NULL), m_capacity(0), m_size(0) { + NV_FORCEINLINE Array(const T * ptr, uint num) : m_buffer(NULL), m_capacity(0), m_size(0) { copy(ptr, num); } @@ -172,8 +109,12 @@ namespace nv #if 1 nvDebugCheck(&val < m_buffer || &val > m_buffer+m_size); - setArraySize(m_size+1); - new(m_buffer+m_size-1) T(val); + uint old_size = m_size; + uint new_size = m_size + 1; + + setArraySize(new_size); + + construct_range(m_buffer, new_size, old_size, val); #else uint new_size = m_size + 1; @@ -205,7 +146,7 @@ namespace nv } /// Qt like push operator. - NV_FORCEINLINE Array & operator<< ( const T & t ) + NV_FORCEINLINE Array & operator<< ( T & t ) { push_back(t); return *this; @@ -360,6 +301,8 @@ namespace nv /// new ones with the given value. void resize(uint new_size, const T & elem) { + nvDebugCheck(&elem < m_buffer || &elem > m_buffer+m_size); + uint old_size = m_size; // Destruct old elements (if we're shrinking). @@ -397,10 +340,13 @@ namespace nv } /// Copy elements to this array. Resizes it if needed. - NV_FORCEINLINE void copy(const T * ptr, uint num) + NV_FORCEINLINE void copy(const T * data, uint count) { - resize( num ); // @@ call copy operator from 0 to min(num,m_size) and copy constructor from min(num,m_size) to num - ::nv::copy(m_buffer, ptr, num); + destroy_range(m_buffer, count, m_size); + + setArraySize(count); + + ::nv::copy(m_buffer, data, count); } /// Assignment operator. @@ -456,13 +402,14 @@ namespace nv #endif // Swap the members of this vector and the given vector. - friend void swap(Array & a, Array & b) + friend void swapMembers(Array & a, Array & b) { - swap(a.m_buffer, b.m_buffer); - swap(a.m_capacity, b.m_capacity); - swap(a.m_size, b.m_size); + nv::swap(a.m_buffer, b.m_buffer); + nv::swap(a.m_capacity, b.m_capacity); + nv::swap(a.m_size, b.m_size); } + protected: // Change array size. @@ -510,6 +457,14 @@ protected: }; + + template + inline void swap(Array & a, Array & b) + { + swapMembers(a, b); + } + + } // nv namespace #endif // NV_CORE_ARRAY_H diff --git a/src/nvcore/Debug.cpp b/src/nvcore/Debug.cpp index 071c8df..fe25788 100644 --- a/src/nvcore/Debug.cpp +++ b/src/nvcore/Debug.cpp @@ -756,3 +756,50 @@ bool debug::isDebuggerPresent() return getsid(getpid()) != getppid(); #endif } + +bool debug::attachToDebugger() +{ +#if NV_OS_WIN32 + if (isDebuggerPresent() == FALSE) { + Path process(1024); + process.copy("\""); + GetSystemDirectory(process.str() + 1, 1024 - 1); + + process.appendSeparator(); + + process.appendFormat("VSJitDebugger.exe\" -p %lu", ::GetCurrentProcessId()); + + STARTUPINFO sSi; + memset(&sSi, 0, sizeof(sSi)); + + PROCESS_INFORMATION sPi; + memset(&sPi, 0, sizeof(sPi)); + + BOOL b = CreateProcess(NULL, process.str(), NULL, NULL, FALSE, 0, NULL, NULL, &sSi, &sPi); + if (b != FALSE) { + ::WaitForSingleObject(sPi.hProcess, INFINITE); + + DWORD dwExitCode; + ::GetExitCodeProcess(sPi.hProcess, &dwExitCode); + if (dwExitCode != 0) //if exit code is zero, a debugger was selected + b = FALSE; + } + + if (sPi.hThread != NULL) ::CloseHandle(sPi.hThread); + if (sPi.hProcess != NULL) ::CloseHandle(sPi.hProcess); + + if (b == FALSE) + return false; + + for (int i = 0; i < 5*60; i++) { + if (isDebuggerPresent()) + break; + ::Sleep(200); + } + } + + nvDebugBreak(); +#endif // NV_OS_WIN32 + + return true; +} \ No newline at end of file diff --git a/src/nvcore/Debug.h b/src/nvcore/Debug.h index c6a0f76..ef87210 100644 --- a/src/nvcore/Debug.h +++ b/src/nvcore/Debug.h @@ -18,9 +18,9 @@ #define NV_ABORT_EXIT 3 #define nvNoAssert(exp) \ - do { \ - (void)sizeof(exp); \ - } while(0) + NV_MULTI_LINE_MACRO_BEGIN \ + (void)sizeof(exp); \ + NV_MULTI_LINE_MACRO_END #if NV_NO_ASSERT @@ -50,42 +50,43 @@ # endif #define nvDebugBreakOnce() \ - do { \ - static bool firstTime = true; \ - if (firstTime) { firstTime = false; nvDebugBreak(); } \ - } while(false) - -# define nvAssertMacro(exp) \ - do { \ - if (!(exp)) { \ - if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \ - nvDebugBreak(); \ - } \ + NV_MULTI_LINE_MACRO_BEGIN \ + static bool firstTime = true; \ + if (firstTime) { firstTime = false; nvDebugBreak(); } \ + NV_MULTI_LINE_MACRO_END + +#define nvAssertMacro(exp) \ + NV_MULTI_LINE_MACRO_BEGIN \ + if (!(exp)) { \ + if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \ + nvDebugBreak(); \ } \ - } while(false) + } \ + NV_MULTI_LINE_MACRO_END -# define nvAssertMacroWithIgnoreAll(exp) \ - do { \ +#define nvAssertMacroWithIgnoreAll(exp) \ + NV_MULTI_LINE_MACRO_BEGIN \ static bool ignoreAll = false; \ if (!ignoreAll && !(exp)) { \ - if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \ + int result = nvAbort(#exp, __FILE__, __LINE__, __FUNC__); \ + if (result == NV_ABORT_DEBUG) { \ nvDebugBreak(); \ - } else { \ + } else if (result == NV_ABORT_IGNORE) { \ ignoreAll = true; \ } \ } \ - } while(false) + NV_MULTI_LINE_MACRO_END -# define nvAssert(exp) nvAssertMacro(exp) -# define nvCheck(exp) nvAssertMacro(exp) +#define nvAssert(exp) nvAssertMacro(exp) +#define nvCheck(exp) nvAssertMacro(exp) -# if defined(_DEBUG) -# define nvDebugAssert(exp) nvAssertMacro(exp) -# define nvDebugCheck(exp) nvAssertMacro(exp) -# else // _DEBUG -# define nvDebugAssert(exp) nvNoAssert(exp) -# define nvDebugCheck(exp) nvNoAssert(exp) -# endif // _DEBUG +#if defined(_DEBUG) +# define nvDebugAssert(exp) nvAssertMacro(exp) +# define nvDebugCheck(exp) nvAssertMacro(exp) +#else // _DEBUG +# define nvDebugAssert(exp) nvNoAssert(exp) +# define nvDebugCheck(exp) nvNoAssert(exp) +#endif // _DEBUG #endif // NV_NO_ASSERT @@ -165,6 +166,7 @@ namespace nv NVCORE_API void disableSigHandler(); NVCORE_API bool isDebuggerPresent(); + NVCORE_API bool attachToDebugger(); } } // nv namespace diff --git a/src/nvcore/ForEach.h b/src/nvcore/ForEach.h index 8207bb0..4a6bf29 100644 --- a/src/nvcore/ForEach.h +++ b/src/nvcore/ForEach.h @@ -5,7 +5,7 @@ #define NV_CORE_FOREACH_H /* -The foreach macros that I use are very non-standard and somewhat confusing, but I like them. +These foreach macros are very non-standard and somewhat confusing, but I like them. */ @@ -32,10 +32,10 @@ struct PseudoIndexWrapper { } // PseudoIndex cannot have a dtor! - template typename T::PseudoIndex & operator()(const T * container) { + template typename T::PseudoIndex & operator()(const T * /*container*/) { return *reinterpret_cast(memory); } - template const typename T::PseudoIndex & operator()(const T * container) const { + template const typename T::PseudoIndex & operator()(const T * /*container*/) const { return *reinterpret_cast(memory); } diff --git a/src/nvcore/StdStream.h b/src/nvcore/StdStream.h index 79912f5..65b91a0 100644 --- a/src/nvcore/StdStream.h +++ b/src/nvcore/StdStream.h @@ -88,7 +88,7 @@ namespace nv uint pos = (uint)ftell(m_fp); fseek(m_fp, 0, SEEK_END); uint end = (uint)ftell(m_fp); - fseek(m_fp, pos, SEEK_SET); + fseek(m_fp, pos, SEEK_SET); #endif return end; } @@ -326,7 +326,7 @@ namespace nv return len; } - virtual void seek( uint pos ) { /*Not implemented*/ } + virtual void seek( uint /*pos*/ ) { /*Not implemented*/ } virtual uint tell() const { return m_buffer.size(); } virtual uint size() const { return m_buffer.size(); } diff --git a/src/nvcore/StrLib.cpp b/src/nvcore/StrLib.cpp index 55b305d..83a8887 100644 --- a/src/nvcore/StrLib.cpp +++ b/src/nvcore/StrLib.cpp @@ -483,7 +483,7 @@ const char * Path::extension() const /// Toggles path separators (ie. \\ into /). -void Path::translatePath(char pathSeparator /*= NV_PATH_SEPARATOR*/) +void Path::translatePath(char pathSeparator/*=NV_PATH_SEPARATOR*/) { nvCheck( m_str != NULL ); @@ -493,6 +493,18 @@ void Path::translatePath(char pathSeparator /*= NV_PATH_SEPARATOR*/) } } +void Path::appendSeparator(char pathSeparator/*=NV_PATH_SEPARATOR*/) +{ + nvCheck(!isNull()); + + const uint l = length(); + + if (m_str[l] != '\\' && m_str[l] != '/') { + char separatorString[] = { pathSeparator, '\0' }; + append(separatorString); + } +} + /** * Strip the file name from a path. diff --git a/src/nvcore/StrLib.h b/src/nvcore/StrLib.h index 65fb759..544fa26 100644 --- a/src/nvcore/StrLib.h +++ b/src/nvcore/StrLib.h @@ -155,6 +155,8 @@ namespace nv void translatePath(char pathSeparator = NV_PATH_SEPARATOR); + void appendSeparator(char pathSeparator = NV_PATH_SEPARATOR); + void stripFileName(); void stripExtension(); diff --git a/src/nvcore/Stream.h b/src/nvcore/Stream.h index f57b42d..d45cd6c 100644 --- a/src/nvcore/Stream.h +++ b/src/nvcore/Stream.h @@ -73,6 +73,9 @@ namespace nv virtual bool isSaving() const = 0; + void advance(uint offset) { seek(tell() + offset); } + + // friends friend Stream & operator<<( Stream & s, bool & c ) { #if NV_OS_DARWIN diff --git a/src/nvcore/Utils.h b/src/nvcore/Utils.h index 4498f34..ed17aba 100644 --- a/src/nvcore/Utils.h +++ b/src/nvcore/Utils.h @@ -13,6 +13,7 @@ #define NV_INT8_MIN (-128) #define NV_INT8_MAX 127 +#define NV_UINT8_MAX 255 #define NV_INT16_MIN (-32767-1) #define NV_INT16_MAX 32767 #define NV_UINT16_MAX 0xffff @@ -27,16 +28,6 @@ namespace nv { // Less error prone than casting. From CB: // http://cbloomrants.blogspot.com/2011/06/06-17-11-c-casting-is-devil.html - inline int8 asSigned(uint8 x) { return (int8) x; } - inline int16 asSigned(uint16 x) { return (int16) x; } - inline int32 asSigned(uint32 x) { return (int32) x; } - inline int64 asSigned(uint64 x) { return (int64) x; } - - inline uint8 asUnsigned(int8 x) { return (uint8) x; } - inline uint16 asUnsigned(int16 x) { return (uint16) x; } - inline uint32 asUnsigned(int32 x) { return (uint32) x; } - inline uint64 asUnsigned(int64 x) { return (uint64) x; } - // uint32 casts: template inline uint32 toU32(T x) { return x; } @@ -60,12 +51,55 @@ namespace nv //template <> inline int32 toI32(uint8 x) { return x; } //template <> inline int32 toI32(int8 x) { return x; } + // uint16 casts: + template inline uint16 toU16(T x) { return x; } + template <> inline uint16 toU16(uint64 x) { nvDebugCheck(x <= NV_UINT16_MAX); return (uint16)x; } + template <> inline uint16 toU16(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT16_MAX); return (uint16)x; } + template <> inline uint16 toU16(uint32 x) { nvDebugCheck(x <= NV_UINT16_MAX); return (uint16)x; } + template <> inline uint16 toU16(int32 x) { nvDebugCheck(x >= 0 && x <= NV_UINT16_MAX); return (uint16)x; } + //template <> inline uint16 toU16(uint16 x) { return x; } + template <> inline uint16 toU16(int16 x) { nvDebugCheck(x >= 0); return (uint16)x; } + //template <> inline uint16 toU16(uint8 x) { return x; } + template <> inline uint16 toU16(int8 x) { nvDebugCheck(x >= 0); return (uint16)x; } + + // int16 casts: + template inline int16 toI16(T x) { return x; } + template <> inline int16 toI16(uint64 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; } + template <> inline int16 toI16(int64 x) { nvDebugCheck(x >= NV_INT16_MIN && x <= NV_UINT16_MAX); return (int16)x; } + template <> inline int16 toI16(uint32 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; } + template <> inline int16 toI16(int32 x) { nvDebugCheck(x >= NV_INT16_MIN && x <= NV_UINT16_MAX); return (int16)x; } + template <> inline int16 toI16(uint16 x) { nvDebugCheck(x <= NV_INT16_MAX); return (int16)x; } + //template <> inline int16 toI16(int16 x) { return x; } + //template <> inline int16 toI16(uint8 x) { return x; } + //template <> inline int16 toI16(int8 x) { return x; } + + // uint8 casts: + template inline uint8 toU8(T x) { return x; } + template <> inline uint8 toU8(uint64 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; } + template <> inline uint8 toU8(int64 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; } + template <> inline uint8 toU8(uint32 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; } + template <> inline uint8 toU8(int32 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; } + template <> inline uint8 toU8(uint16 x) { nvDebugCheck(x <= NV_UINT8_MAX); return (uint8)x; } + template <> inline uint8 toU8(int16 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; } + //template <> inline uint8 toU8(uint8 x) { return x; } + template <> inline uint8 toU8(int8 x) { nvDebugCheck(x >= 0 && x <= NV_UINT8_MAX); return (uint8)x; } + + // int8 casts: + template inline int8 toI8(T x) { return x; } + template <> inline int8 toI8(uint64 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; } + template <> inline int8 toI8(int64 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; } + template <> inline int8 toI8(uint32 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; } + template <> inline int8 toI8(int32 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; } + template <> inline int8 toI8(uint16 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; } + template <> inline int8 toI8(int16 x) { nvDebugCheck(x >= NV_INT8_MIN && x <= NV_UINT8_MAX); return (int8)x; } + template <> inline int8 toI8(uint8 x) { nvDebugCheck(x <= NV_INT8_MAX); return (int8)x; } + //template <> inline int8 toI8(int8 x) { return x; } /// Swap two values. template inline void swap(T & a, T & b) { - T temp = a; + T temp(a); a = b; b = temp; } @@ -191,6 +225,67 @@ namespace nv }; + // @@ Move this to utils? + /// Delete all the elements of a container. + template + void deleteAll(T & container) + { + for (typename T::PseudoIndex i = container.start(); !container.isDone(i); container.advance(i)) + { + delete container[i]; + } + } + + + + // @@ Specialize these methods for numeric, pointer, and pod types. + + template + void construct_range(T * restrict ptr, uint new_size, uint old_size) { + for (uint i = old_size; i < new_size; i++) { + new(ptr+i) T; // placement new + } + } + + template + void construct_range(T * restrict ptr, uint new_size, uint old_size, const T & elem) { + for (uint i = old_size; i < new_size; i++) { + new(ptr+i) T(elem); // placement new + } + } + + template + void destroy_range(T * restrict ptr, uint new_size, uint old_size) { + for (uint i = new_size; i < old_size; i++) { + (ptr+i)->~T(); // Explicit call to the destructor + } + } + + template + void fill(T * restrict dst, uint count, const T & value) { + for (uint i = 0; i < count; i++) { + dst[i] = value; + } + } + + template + void copy(T * restrict dst, const T * restrict src, uint count) { + for (uint i = 0; i < count; i++) { + dst[i] = src[i]; + } + } + + template + bool find(const T & element, const T * restrict ptr, uint begin, uint end, uint * index) { + for (uint i = begin; i < end; i++) { + if (ptr[i] == element) { + if (index != NULL) *index = i; + return true; + } + } + return false; + } + } // nv namespace #endif // NV_CORE_UTILS_H diff --git a/src/nvcore/nvcore.h b/src/nvcore/nvcore.h index fa28cca..a4ebd89 100644 --- a/src/nvcore/nvcore.h +++ b/src/nvcore/nvcore.h @@ -90,7 +90,7 @@ #if defined POSH_COMPILER_CLANG # define NV_CC_CLANG 1 -# define NV_CC_GCC 1 // Clang is compatible with GCC. +# define NV_CC_GNUC 1 // Clang is compatible with GCC. # define NV_CC_STRING "clang" #elif defined POSH_COMPILER_GCC # define NV_CC_GNUC 1 @@ -168,6 +168,17 @@ typedef uint32 uint; #define NV_STRING2(x) #x #define NV_STRING(x) NV_STRING2(x) +#if NV_CC_MSVC +#define NV_MULTI_LINE_MACRO_BEGIN do { +#define NV_MULTI_LINE_MACRO_END \ + __pragma(warning(push)) \ + __pragma(warning(disable:4127)) \ + } while(false) \ + __pragma(warning(pop)) +#else +#define NV_MULTI_LINE_MACRO_BEGIN do { +#define NV_MULTI_LINE_MACRO_END } while(false) +#endif #if __cplusplus > 199711L #define nvStaticCheck(x) static_assert(x)