diff --git a/src/nvcore/Algorithms.h b/src/nvcore/Algorithms.h deleted file mode 100644 index ee69af5..0000000 --- a/src/nvcore/Algorithms.h +++ /dev/null @@ -1,154 +0,0 @@ -// This code is in the public domain -- castanyo@yahoo.es - -#ifndef NV_CORE_ALGORITHMS_H -#define NV_CORE_ALGORITHMS_H - -#include "nvcore.h" - -namespace nv -{ - - /// Return the maximum of two values. - template - inline const T & max(const T & a, const T & b) - { - //return std::max(a, b); - if( a < b ) { - return b; - } - return a; - } - - /// Return the minimum of two values. - template - inline const T & min(const T & a, const T & b) - { - //return std::min(a, b); - if( b < a ) { - return b; - } - return a; - } - - /// Clamp between two values. - template - inline const T & clamp(const T & x, const T & a, const T & b) - { - return min(max(x, a), b); - } - - /// 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]; - } - } - - // @@ Should swap be implemented here? - - - - template class C> - void sort(C & container) - { - introsortLoop(container, 0, container.count()); - insertionSort(container, 0, container.count()); - } - - template class C> - void sort(C & container, uint begin, uint end) - { - if (begin < end) - { - introsortLoop(container, begin, end); - insertionSort(container, begin, end); - } - } - - template class C> - void insertionSort(C & container) - { - insertionSort(container, 0, container.count()); - } - - template class C> - void insertionSort(C & container, uint begin, uint end) - { - for (uint i = begin + 1; i != end; ++i) - { - T value = container[i]; - - uint j = i; - while (j != begin && container[j-1] > value) - { - container[j] = container[j-1]; - --j; - } - if (i != j) - { - container[j] = value; - } - } - } - - template class C> - void introsortLoop(C & container, uint begin, uint end) - { - while (end-begin > 16) - { - uint p = partition(container, begin, end, medianof3(container, begin, begin+((end-begin)/2)+1, end-1)); - introsortLoop(container, p, end); - end = p; - } - } - - template class C> - uint partition(C & a, uint begin, uint end, const T & x) - { - int i = begin, j = end; - while (true) - { - while (a[i] < x) ++i; - --j; - while (x < a[j]) --j; - if (i >= j) - return i; - swap(a[i], a[j]); - i++; - } - } - - template class C> - const T & medianof3(C & a, uint lo, uint mid, uint hi) - { - if (a[mid] < a[lo]) - { - if (a[hi] < a[mid]) - { - return a[mid]; - } - else - { - return (a[hi] < a[lo]) ? a[hi] : a[lo]; - } - } - else - { - if (a[hi] < a[mid]) - { - return (a[hi] < a[lo]) ? a[lo] : a[hi]; - } - else - { - return a[mid]; - } - } - } - - -} // nv namespace - -#endif // NV_CORE_ALGORITHMS_H diff --git a/src/nvcore/Array.h b/src/nvcore/Array.h new file mode 100644 index 0000000..3759b6f --- /dev/null +++ b/src/nvcore/Array.h @@ -0,0 +1,525 @@ +// This code is in the public domain -- Ignacio Castaņo + +#pragma once +#ifndef NV_CORE_ARRAY_H +#define NV_CORE_ARRAY_H + +/* +This array class requires the elements to be relocable; it uses memmove and realloc. Ideally I should be +using swap, but I honestly don't care. + +The foreach macros that I use are very non-standard and somewhat confusing. It would be nice to have +standard foreach as in Qt. +*/ + + +#include "nvcore.h" +#include "Memory.h" +#include "Debug.h" +#include "Stream.h" +#include "Utils.h" // swap + +#include // memmove +#include // for placement new + + +#if NV_CC_GNUC // If typeof is available: + +#define NV_FOREACH(i, container) \ + typedef typeof(container) NV_STRING_JOIN2(cont,__LINE__); \ + for(NV_STRING_JOIN2(cont,__LINE__)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i)) +/* +#define NV_FOREACH(i, container) \ +for(typename typeof(container)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i)) +*/ + +#else // If typeof not available: + +struct PseudoIndexWrapper { + template + PseudoIndexWrapper(const T & container) { + nvStaticCheck(sizeof(typename T::PseudoIndex) <= sizeof(memory)); + new (memory) typename T::PseudoIndex(container.start()); + } + // PseudoIndex cannot have a dtor! + + template typename T::PseudoIndex & operator()(const T * container) { + return *reinterpret_cast(memory); + } + template const typename T::PseudoIndex & operator()(const T * container) const { + return *reinterpret_cast(memory); + } + + uint8 memory[4]; // Increase the size if we have bigger enumerators. +}; + +#define NV_FOREACH(i, container) \ + for(PseudoIndexWrapper i(container); !(container).isDone(i(&(container))); (container).advance(i(&(container)))) + +#endif + +// Declare foreach keyword. +#if !defined NV_NO_USE_KEYWORDS +# define foreach NV_FOREACH +#endif + + + +namespace nv +{ + /// 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]; + } + } + + + + /** + * Replacement for std::vector that is easier to debug and provides + * some nice foreach enumerators. + */ + template + class NVCORE_CLASS Array { + public: + + /// Ctor. + Array() : m_buffer(NULL), m_size(0), m_buffer_size(0) + { + } + + /// Copy ctor. + Array( const Array & a ) : m_buffer(NULL), m_size(0), m_buffer_size(0) + { + copy(a.m_buffer, a.m_size); + } + + /// Ctor that initializes the vector with the given elements. + Array( const T * ptr, int num ) : m_buffer(NULL), m_size(0), m_buffer_size(0) + { + copy(ptr, num); + } + + /// Allocate array. + explicit Array(uint capacity) : m_buffer(NULL), m_size(0), m_buffer_size(0) + { + allocate(capacity); + } + + + /// Dtor. + ~Array() + { + clear(); + allocate(0); + } + + + /// Const element access. + const T & operator[]( uint index ) const + { + nvDebugCheck(index < m_size); + return m_buffer[index]; + } + const T & at( uint index ) const + { + nvDebugCheck(index < m_size); + return m_buffer[index]; + } + + /// Element access. + T & operator[] ( uint index ) + { + nvDebugCheck(index < m_size); + return m_buffer[index]; + } + T & at( uint index ) + { + nvDebugCheck(index < m_size); + return m_buffer[index]; + } + + /// Get vector size. + uint size() const { return m_size; } + + /// Get vector size. + uint count() const { return m_size; } + + /// Get const vector pointer. + const T * buffer() const { return m_buffer; } + + /// Get vector pointer. + T * mutableBuffer() { return m_buffer; } + + /// Is vector empty. + bool isEmpty() const { return m_size == 0; } + + /// Is a null vector. + bool isNull() const { return m_buffer == NULL; } + + + /// Push an element at the end of the vector. + void push_back( const T & val ) + { + uint new_size = m_size + 1; + + if (new_size > m_buffer_size) + { + const T copy(val); // create a copy in case value is inside of this array. + resize(new_size); + m_buffer[new_size-1] = copy; + } + else + { + m_size = new_size; + new(m_buffer+new_size-1) T(val); + } + } + void pushBack( const T & val ) + { + push_back(val); + } + void append( const T & val ) + { + push_back(val); + } + + /// Qt like push operator. + Array & operator<< ( T & t ) + { + push_back(t); + return *this; + } + + /// Pop and return element at the end of the vector. + void pop_back() + { + nvDebugCheck( m_size > 0 ); + resize( m_size - 1 ); + } + void popBack() + { + pop_back(); + } + + /// Get back element. + const T & back() const + { + nvDebugCheck( m_size > 0 ); + return m_buffer[m_size-1]; + } + + /// Get back element. + T & back() + { + nvDebugCheck( m_size > 0 ); + return m_buffer[m_size-1]; + } + + /// Get front element. + const T & front() const + { + nvDebugCheck( m_size > 0 ); + return m_buffer[0]; + } + + /// Get front element. + T & front() + { + nvDebugCheck( m_size > 0 ); + return m_buffer[0]; + } + + /// Return true if element found. + bool find(const T & element, uint * index) + { + return find(element, 0, m_size, index); + } + + /// Return true if element found within the given range. + bool find(const T & element, uint first, uint count, uint * index) + { + for (uint i = first; i < first+count; i++) { + if (m_buffer[i] == element) { + if (index != NULL) *index = i; + return true; + } + } + return false; + } + + /// Check if the given element is contained in the array. + bool contains(const T & e) const + { + return find(e, NULL); + } + + /// Remove the element at the given index. This is an expensive operation! + void removeAt( uint index ) + { + nvCheck(index >= 0 && index < m_size); + + if( m_size == 1 ) { + clear(); + } + else { + m_buffer[index].~T(); + + memmove( m_buffer+index, m_buffer+index+1, sizeof(T) * (m_size - 1 - index) ); + m_size--; + } + } + + /// Remove the first instance of the given element. + void remove(const T & element) + { + for (uint i = 0; i < m_size; i++) { + removeAt(i); + break; + } + } + + /// Insert the given element at the given index shifting all the elements up. + void insertAt( uint index, const T & val = T() ) + { + nvCheck( index >= 0 && index <= m_size ); + + resize( m_size + 1 ); + + if( index < m_size - 1 ) { + memmove( m_buffer+index+1, m_buffer+index, sizeof(T) * (m_size - 1 - index) ); + } + + // Copy-construct into the newly opened slot. + new(m_buffer+index) T(val); + } + + /// Append the given data to our vector. + void append(const Array & other) + { + append(other.m_buffer, other.m_size); + } + + /// Append the given data to our vector. + void append(const T other[], uint count) + { + if( count > 0 ) { + const uint old_size = m_size; + resize(m_size + count); + // Must use operator=() to copy elements, in case of side effects (e.g. ref-counting). + for( uint i = 0; i < count; i++ ) { + m_buffer[old_size + i] = other[i]; + } + } + } + + + /// Remove the given element by replacing it with the last one. + void replaceWithLast(uint index) + { + nvDebugCheck( index < m_size ); + swap(m_buffer[index], back()); + //m_buffer[index] = back(); + (m_buffer+m_size-1)->~T(); + m_size--; + } + + + /// Resize the vector preserving existing elements. + void resize(uint new_size) + { + uint i; + uint old_size = m_size; + m_size = new_size; + + // Destruct old elements (if we're shrinking). + for( i = new_size; i < old_size; i++ ) { + (m_buffer+i)->~T(); // Explicit call to the destructor + } + + if( m_size == 0 ) { + //Allocate(0); // Don't shrink automatically. + } + else if( m_size <= m_buffer_size/* && m_size > m_buffer_size >> 1*/) { + // don't compact yet. + nvDebugCheck(m_buffer != NULL); + } + else { + uint new_buffer_size; + if( m_buffer_size == 0 ) { + // first allocation + new_buffer_size = m_size; + } + else { + // growing + new_buffer_size = m_size + (m_size >> 2); + } + allocate( new_buffer_size ); + } + + // Call default constructors + for( i = old_size; i < new_size; i++ ) { + new(m_buffer+i) T; // placement new + } + } + + + /// Resize the vector preserving existing elements and initializing the + /// new ones with the given value. + void resize( uint new_size, const T &elem ) + { + uint i; + uint old_size = m_size; + m_size = new_size; + + // Destruct old elements (if we're shrinking). + for( i = new_size; i < old_size; i++ ) { + (m_buffer+i)->~T(); // Explicit call to the destructor + } + + if( m_size == 0 ) { + //Allocate(0); // Don't shrink automatically. + } + else if( m_size <= m_buffer_size && m_size > m_buffer_size >> 1 ) { + // don't compact yet. + } + else { + uint new_buffer_size; + if( m_buffer_size == 0 ) { + // first allocation + new_buffer_size = m_size; + } + else { + // growing + new_buffer_size = m_size + (m_size >> 2); + } + allocate( new_buffer_size ); + } + + // Call copy constructors + for( i = old_size; i < new_size; i++ ) { + new(m_buffer+i) T( elem ); // placement new + } + } + + /// Clear the buffer. + void clear() + { + resize(0); + } + + /// Shrink the allocated vector. + void shrink() + { + if (m_size < m_buffer_size) { + allocate(m_size); + } + } + + /// Preallocate space. + void reserve(uint desired_size) + { + if (desired_size > m_buffer_size) { + allocate( desired_size ); + } + } + + /// Copy elements to this array. Resizes it if needed. + void copy(const T * ptr, uint num) + { + resize( num ); + for (uint i = 0; i < m_size; i++) { + m_buffer[i] = ptr[i]; + } + } + + /// Assignment operator. + Array & operator=( const Array & a ) + { + copy(a.m_buffer, a.m_size); + return *this; + } + + + /// Array serialization. + friend Stream & operator<< ( Stream & s, Array & p ) + { + if( s.isLoading() ) { + uint size; + s << size; + p.resize( size ); + } + else { + s << p.m_size; + } + + for( uint i = 0; i < p.m_size; i++ ) { + s << p.m_buffer[i]; + } + + return s; + } + + + // Array enumerator. + typedef uint PseudoIndex; + + PseudoIndex start() const { return 0; } + bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); return i == this->m_size; }; + void advance(PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); i++; } + +#if NV_CC_MSVC + T & operator[]( const PseudoIndexWrapper & i ) { + return m_buffer[i(this)]; + } + const T & operator[]( const PseudoIndexWrapper & i ) const { + return m_buffer[i(this)]; + } +#endif + + + /// Swap the members of this vector and the given vector. + friend void swap(Array & a, Array & b) + { + swap(a.m_buffer, b.m_buffer); + swap(a.m_size, b.m_size); + swap(a.m_buffer_size, b.m_buffer_size); + } + + + private: + + /// Change buffer size. + void allocate( uint rsize ) + { + m_buffer_size = rsize; + + // free the buffer. + if (m_buffer_size == 0) { + if (m_buffer) { + mem::free( m_buffer ); + m_buffer = NULL; + } + } + + // realloc the buffer + else { + if (m_buffer) m_buffer = (T *) mem::realloc( m_buffer, sizeof(T) * m_buffer_size ); + else m_buffer = (T *) mem::malloc( sizeof(T) * m_buffer_size ); + } + } + + + private: + T * m_buffer; + uint m_size; + uint m_buffer_size; + }; + +} // nv namespace + +#endif // NV_CORE_ARRAY_H diff --git a/src/nvcore/CMakeLists.txt b/src/nvcore/CMakeLists.txt index 46b209b..8cfd839 100644 --- a/src/nvcore/CMakeLists.txt +++ b/src/nvcore/CMakeLists.txt @@ -2,8 +2,8 @@ PROJECT(nvcore) SET(CORE_SRCS nvcore.h - Algorithms.h - Containers.h + Utils.h + Array.h HashMap.h Debug.h Debug.cpp DefsGnucDarwin.h DefsGnucLinux.h @@ -13,7 +13,7 @@ SET(CORE_SRCS Library.h Library.cpp Memory.h Memory.cpp Ptr.h - RefCounted.h RefCounted.cpp + RefCounted.h StrLib.h StrLib.cpp Stream.h StdStream.h @@ -27,7 +27,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_DEFINITIONS(-DNVCORE_EXPORTS) IF(UNIX) - SET(LIBS ${LIBS} ${CMAKE_DL_LIBS}) + SET(LIBS ${LIBS} ${CMAKE_DL_LIBS}) ENDIF(UNIX) IF(NVCORE_SHARED) diff --git a/src/nvcore/Containers.h b/src/nvcore/Containers.h deleted file mode 100644 index ac0cbae..0000000 --- a/src/nvcore/Containers.h +++ /dev/null @@ -1,1053 +0,0 @@ -// This code is in the public domain -- castanyo@yahoo.es - -#ifndef NV_CORE_CONTAINER_H -#define NV_CORE_CONTAINER_H - -/* -These containers are based on Thatcher Ulrich containers, -donated to the Public Domain. - -I've also borrowed some ideas from the Qt toolkit, specially the cool -foreach iterator. - -TODO -Do not use memmove in insert & remove, use copy ctors instead. -*/ - - -// nvcore -#include "nvcore.h" -#include "Memory.h" -#include "Debug.h" -//#include "Stream.h" - -#include // memmove -#include // for placement new - - -#if NV_CC_GNUC // If typeof is available: - -#define NV_FOREACH(i, container) \ - typedef typeof(container) NV_STRING_JOIN2(cont,__LINE__); \ - for(NV_STRING_JOIN2(cont,__LINE__)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i)) -/* -#define NV_FOREACH(i, container) \ - for(typename typeof(container)::PseudoIndex i((container).start()); !(container).isDone(i); (container).advance(i)) -*/ - -#else // If typeof not available: - -struct PseudoIndexWrapper { - template - PseudoIndexWrapper(const T & container) { - nvStaticCheck(sizeof(typename T::PseudoIndex) <= sizeof(memory)); - new (memory) typename T::PseudoIndex(container.start()); - } - // PseudoIndex cannot have a dtor! - - template typename T::PseudoIndex & operator()(const T * container) { - return *reinterpret_cast(memory); - } - template const typename T::PseudoIndex & operator()(const T * container) const { - return *reinterpret_cast(memory); - } - - uint8 memory[4]; // Increase the size if we have bigger enumerators. -}; - -#define NV_FOREACH(i, container) \ - for(PseudoIndexWrapper i(container); !(container).isDone(i(&(container))); (container).advance(i(&(container)))) - -#endif - -// Declare foreach keyword. -#if !defined NV_NO_USE_KEYWORDS -# define foreach NV_FOREACH -#endif - - - -namespace nv -{ - // Templates - - /// Swap two values. - template - inline void swap(T & a, T & b) - { - T temp = a; - a = b; - b = temp; - } - - template struct hash - { - inline uint sdbm_hash(const void * data_in, uint size, uint h = 5381) - { - const uint8 * data = (const uint8 *) data_in; - uint i = 0; - while (i < size) { - h = (h << 16) + (h << 6) - h + (uint) data[i++]; - } - return h; - } - - uint operator()(const Key & k) { - return sdbm_hash(&k, sizeof(Key)); - } - }; - template <> struct hash - { - uint operator()(int x) const { return x; } - }; - template <> struct hash - { - uint operator()(uint x) const { return x; } - }; - - - /** Return the next power of two. - * @see http://graphics.stanford.edu/~seander/bithacks.html - * @warning Behaviour for 0 is undefined. - * @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x - * @note nextPowerOfTwo(x) = 2 << log2(x-1) - */ - inline uint nextPowerOfTwo( uint x ) - { - nvDebugCheck( x != 0 ); - #if 1 // On modern CPUs this is supposed to be as fast as using the bsr instruction. - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x+1; - #else - uint p = 1; - while( x > p ) { - p += p; - } - return p; - #endif - } - - /// Return true if @a n is a power of two. - inline bool isPowerOfTwo( uint n ) - { - return (n & (n-1)) == 0; - } - - - /** - * Replacement for std::vector that is easier to debug and provides - * some nice foreach enumerators. - */ - template - class NVCORE_CLASS Array { - public: - - /// Ctor. - Array() : m_buffer(NULL), m_size(0), m_buffer_size(0) - { - } - - /// Copy ctor. - Array( const Array & a ) : m_buffer(NULL), m_size(0), m_buffer_size(0) - { - copy(a.m_buffer, a.m_size); - } - - /// Ctor that initializes the vector with the given elements. - Array( const T * ptr, int num ) : m_buffer(NULL), m_size(0), m_buffer_size(0) - { - copy(ptr, num); - } - - /// Allocate array. - explicit Array(uint capacity) : m_buffer(NULL), m_size(0), m_buffer_size(0) - { - allocate(capacity); - } - - - /// Dtor. - ~Array() - { - clear(); - allocate(0); - } - - - /// Const element access. - const T & operator[]( uint index ) const - { - nvDebugCheck(index < m_size); - return m_buffer[index]; - } - const T & at( uint index ) const - { - nvDebugCheck(index < m_size); - return m_buffer[index]; - } - - /// Element access. - T & operator[] ( uint index ) - { - nvDebugCheck(index < m_size); - return m_buffer[index]; - } - T & at( uint index ) - { - nvDebugCheck(index < m_size); - return m_buffer[index]; - } - - /// Get vector size. - uint size() const { return m_size; } - - /// Get vector size. - uint count() const { return m_size; } - - /// Get const vector pointer. - const T * buffer() const { return m_buffer; } - - /// Get vector pointer. - T * mutableBuffer() { return m_buffer; } - - /// Is vector empty. - bool isEmpty() const { return m_size == 0; } - - /// Is a null vector. - bool isNull() const { return m_buffer == NULL; } - - - /// Push an element at the end of the vector. - void push_back( const T & val ) - { - uint new_size = m_size + 1; - - if (new_size > m_buffer_size) - { - const T copy(val); // create a copy in case value is inside of this array. - resize(new_size); - m_buffer[new_size-1] = copy; - } - else - { - m_size = new_size; - new(m_buffer+new_size-1) T(val); - } - } - void pushBack( const T & val ) - { - push_back(val); - } - void append( const T & val ) - { - push_back(val); - } - - /// Qt like push operator. - Array & operator<< ( T & t ) - { - push_back(t); - return *this; - } - - /// Pop and return element at the end of the vector. - void pop_back() - { - nvDebugCheck( m_size > 0 ); - resize( m_size - 1 ); - } - void popBack() - { - pop_back(); - } - - /// Get back element. - const T & back() const - { - nvDebugCheck( m_size > 0 ); - return m_buffer[m_size-1]; - } - - /// Get back element. - T & back() - { - nvDebugCheck( m_size > 0 ); - return m_buffer[m_size-1]; - } - - /// Get front element. - const T & front() const - { - nvDebugCheck( m_size > 0 ); - return m_buffer[0]; - } - - /// Get front element. - T & front() - { - nvDebugCheck( m_size > 0 ); - return m_buffer[0]; - } - - /// Return index of the - bool find(const T & element, uint * index) - { - for (uint i = 0; i < m_size; i++) { - if (index != NULL) *index = i; - return true; - } - return false; - } - - /// Check if the given element is contained in the array. - bool contains(const T & e) const - { - return find(e, NULL); - } - - /// Remove the element at the given index. This is an expensive operation! - void removeAt( uint index ) - { - nvCheck(index >= 0 && index < m_size); - - if( m_size == 1 ) { - clear(); - } - else { - m_buffer[index].~T(); - - memmove( m_buffer+index, m_buffer+index+1, sizeof(T) * (m_size - 1 - index) ); - m_size--; - } - } - - /// Remove the first instance of the given element. - void remove(const T & element) - { - for(PseudoIndex i = start(); !isDone(i); advance(i)) { - removeAt(i); - break; - } - } - - /// Insert the given element at the given index shifting all the elements up. - void insertAt( uint index, const T & val = T() ) - { - nvCheck( index >= 0 && index <= m_size ); - - resize( m_size + 1 ); - - if( index < m_size - 1 ) { - memmove( m_buffer+index+1, m_buffer+index, sizeof(T) * (m_size - 1 - index) ); - } - - // Copy-construct into the newly opened slot. - new(m_buffer+index) T(val); - } - - /// Append the given data to our vector. - void append(const Array & other) - { - append(other.m_buffer, other.m_size); - } - - /// Append the given data to our vector. - void append(const T other[], uint count) - { - if( count > 0 ) { - const uint old_size = m_size; - resize(m_size + count); - // Must use operator=() to copy elements, in case of side effects (e.g. ref-counting). - for( uint i = 0; i < count; i++ ) { - m_buffer[old_size + i] = other[i]; - } - } - } - - - /// Remove the given element by replacing it with the last one. - void replaceWithLast(uint index) - { - nvDebugCheck( index < m_size ); - m_buffer[index] = back(); - (m_buffer+m_size-1)->~T(); - m_size--; - } - - - /// Resize the vector preserving existing elements. - void resize(uint new_size) - { - uint i; - uint old_size = m_size; - m_size = new_size; - - // Destruct old elements (if we're shrinking). - for( i = new_size; i < old_size; i++ ) { - (m_buffer+i)->~T(); // Explicit call to the destructor - } - - if( m_size == 0 ) { - //Allocate(0); // Don't shrink automatically. - } - else if( m_size <= m_buffer_size/* && m_size > m_buffer_size >> 1*/) { - // don't compact yet. - nvDebugCheck(m_buffer != NULL); - } - else { - uint new_buffer_size; - if( m_buffer_size == 0 ) { - // first allocation - new_buffer_size = m_size; - } - else { - // growing - new_buffer_size = m_size + (m_size >> 2); - } - allocate( new_buffer_size ); - } - - // Call default constructors - for( i = old_size; i < new_size; i++ ) { - new(m_buffer+i) T; // placement new - } - } - - - /// Resize the vector preserving existing elements and initializing the - /// new ones with the given value. - void resize( uint new_size, const T &elem ) - { - uint i; - uint old_size = m_size; - m_size = new_size; - - // Destruct old elements (if we're shrinking). - for( i = new_size; i < old_size; i++ ) { - (m_buffer+i)->~T(); // Explicit call to the destructor - } - - if( m_size == 0 ) { - //Allocate(0); // Don't shrink automatically. - } - else if( m_size <= m_buffer_size && m_size > m_buffer_size >> 1 ) { - // don't compact yet. - } - else { - uint new_buffer_size; - if( m_buffer_size == 0 ) { - // first allocation - new_buffer_size = m_size; - } - else { - // growing - new_buffer_size = m_size + (m_size >> 2); - } - allocate( new_buffer_size ); - } - - // Call copy constructors - for( i = old_size; i < new_size; i++ ) { - new(m_buffer+i) T( elem ); // placement new - } - } - - /// Tighten the memory used by the container. - void tighten() - { - // TODO Reallocate only if worth. - } - - /// Clear the buffer. - void clear() - { - resize(0); - } - - /// Shrink the allocated vector. - void shrink() - { - if( m_size < m_buffer_size ) { - allocate(m_size); - } - } - - /// Preallocate space. - void reserve(uint desired_size) - { - if( desired_size > m_buffer_size ) { - allocate( desired_size ); - } - } - - /// Copy memory to our vector. Resizes the vector if needed. - void copy( const T * ptr, uint num ) - { - resize( num ); - for(uint i = 0; i < m_size; i++) { - m_buffer[i] = ptr[i]; - } - } - - /// Assignment operator. - Array & operator=( const Array & a ) - { - copy( a.m_buffer, a.m_size ); - return *this; - } - - /* - /// Array serialization. - friend Stream & operator<< ( Stream & s, Array & p ) - { - if( s.isLoading() ) { - uint size; - s << size; - p.resize( size ); - } - else { - s << p.m_size; - } - - for( uint i = 0; i < p.m_size; i++ ) { - s << p.m_buffer[i]; - } - - return s; - } - */ - - // Array enumerator. - typedef uint PseudoIndex; - - PseudoIndex start() const { return 0; } - bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); return i == this->m_size; }; - void advance(PseudoIndex & i) const { nvDebugCheck(i <= this->m_size); i++; } - - #if NV_CC_MSVC - T & operator[]( const PseudoIndexWrapper & i ) { - return m_buffer[i(this)]; - } - const T & operator[]( const PseudoIndexWrapper & i ) const { - return m_buffer[i(this)]; - } - #endif - - - /// Swap the members of this vector and the given vector. - friend void swap(Array & a, Array & b) - { - swap(a.m_buffer, b.m_buffer); - swap(a.m_size, b.m_size); - swap(a.m_buffer_size, b.m_buffer_size); - } - - - private: - - /// Change buffer size. - void allocate( uint rsize ) - { - m_buffer_size = rsize; - - // free the buffer. - if( m_buffer_size == 0 ) { - if( m_buffer ) { - mem::free( m_buffer ); - m_buffer = NULL; - } - } - - // realloc the buffer - else { - if( m_buffer ) m_buffer = (T *) mem::realloc( m_buffer, sizeof(T) * m_buffer_size ); - else m_buffer = (T *) mem::malloc( sizeof(T) * m_buffer_size ); - } - } - - - private: - T * m_buffer; - uint m_size; - uint m_buffer_size; - }; - - - - /** Thatcher Ulrich's hash table. - * - * Hash table, linear probing, internal chaining. One - * interesting/nice thing about this implementation is that the table - * itself is a flat chunk of memory containing no pointers, only - * relative indices. If the key and value types of the hash contain - * no pointers, then the hash can be serialized using raw IO. Could - * come in handy. - * - * Never shrinks, unless you explicitly clear() it. Expands on - * demand, though. For best results, if you know roughly how big your - * table will be, default it to that size when you create it. - */ - template > - class NVCORE_CLASS HashMap - { - public: - - /// Default ctor. - HashMap() : entry_count(0), size_mask(-1), table(NULL) { } - - // Copy ctor. - HashMap(const HashMap & map) : entry_count(0), size_mask(-1), table(NULL) - { - operator = (map); - } - - /// Ctor with size hint. - explicit HashMap(int size_hint) : entry_count(0), size_mask(-1), table(NULL) { setCapacity(size_hint); } - - /// Dtor. - ~HashMap() { clear(); } - - // Assignment operator. - void operator= (const HashMap & map) - { - clear(); - - if (entry_count > 0) - { - entry_count = map.entry_count; - size_mask = map.size_mask; - - const uint size = uint(size_mask + 1); - table = (Entry *)nv::mem::malloc(sizeof(Entry) * size); - - // Copy elements using copy ctor. - for (uint i = 0; i < size; i++) - { - new (table + i) Entry(map.table[i]); - } - } - } - - /// Set a new or existing value under the key, to the value. - void set(const T& key, const U& value) - { - int index = findIndex(key); - if (index >= 0) - { - E(index).value = value; - return; - } - - // Entry under key doesn't exist. - add(key, value); - } - - - /// Add a new value to the hash table, under the specified key. - void add(const T& key, const U& value) - { - nvCheck(findIndex(key) == -1); - - checkExpand(); - nvCheck(table != NULL); - entry_count++; - - const uint hash_value = hash_functor()(key); - const int index = hash_value & size_mask; - - Entry * natural_entry = &(E(index)); - - if (natural_entry->isEmpty()) - { - // Put the new entry in. - new (natural_entry) Entry(key, value, -1, hash_value); - } - else - { - // Find a blank spot. - int blank_index = index; - for (;;) - { - blank_index = (blank_index + 1) & size_mask; - if (E(blank_index).isEmpty()) break; // found it - } - Entry * blank_entry = &E(blank_index); - - if (int(natural_entry->hash_value & size_mask) == index) - { - // Collision. Link into this chain. - - // Move existing list head. - new (blank_entry) Entry(*natural_entry); // placement new, copy ctor - - // Put the new info in the natural entry. - natural_entry->key = key; - natural_entry->value = value; - natural_entry->next_in_chain = blank_index; - natural_entry->hash_value = hash_value; - } - else - { - // Existing entry does not naturally - // belong in this slot. Existing - // entry must be moved. - - // Find natural location of collided element (i.e. root of chain) - int collided_index = natural_entry->hash_value & size_mask; - for (;;) - { - Entry * e = &E(collided_index); - if (e->next_in_chain == index) - { - // Here's where we need to splice. - new (blank_entry) Entry(*natural_entry); - e->next_in_chain = blank_index; - break; - } - collided_index = e->next_in_chain; - nvCheck(collided_index >= 0 && collided_index <= size_mask); - } - - // Put the new data in the natural entry. - natural_entry->key = key; - natural_entry->value = value; - natural_entry->hash_value = hash_value; - natural_entry->next_in_chain = -1; - } - } - } - - - /// Remove the first value under the specified key. - bool remove(const T& key) - { - if (table == NULL) - { - return false; - } - - int index = findIndex(key); - if (index < 0) - { - return false; - } - - Entry * entry = &E(index); - - if( entry->isEndOfChain() ) { - entry->clear(); - } - else { - // Get next entry. - Entry & next_entry = E(entry->next_in_chain); - - // Copy next entry in this place. - new (entry) Entry(next_entry); - - next_entry.clear(); - } - - entry_count--; - - return true; - } - - - /// Remove all entries from the hash table. - void clear() - { - if (table != NULL) - { - // Delete the entries. - for (int i = 0, n = size_mask; i <= n; i++) - { - Entry * e = &E(i); - if (e->isEmpty() == false) - { - e->clear(); - } - } - mem::free(table); - table = NULL; - entry_count = 0; - size_mask = -1; - } - } - - - /// Returns true if the hash is empty. - bool isEmpty() const - { - return table == NULL || entry_count == 0; - } - - - /** Retrieve the value under the given key. - * - * If there's no value under the key, then return false and leave - * *value alone. - * - * If there is a value, return true, and set *value to the entry's - * value. - * - * If value == NULL, return true or false according to the - * presence of the key, but don't touch *value. - */ - bool get(const T& key, U* value = NULL) const - { - int index = findIndex(key); - if (index >= 0) - { - if (value) { - *value = E(index).value; // take care with side-effects! - } - return true; - } - return false; - } - - /// Determine if the given key is contained in the hash. - bool contains(const T & key) const - { - return get(key); - } - - /// Number of entries in the hash. - int size() const - { - return entry_count; - } - - /// Number of entries in the hash. - int count() const - { - return size(); - } - - - /** - * Resize the hash table to fit one more entry. Often this - * doesn't involve any action. - */ - void checkExpand() - { - if (table == NULL) { - // Initial creation of table. Make a minimum-sized table. - setRawCapacity(16); - } - else if (entry_count * 3 > (size_mask + 1) * 2) { - // Table is more than 2/3rds full. Expand. - setRawCapacity(entry_count * 2); - } - } - - - /// Hint the bucket count to >= n. - void resize(int n) - { - // Not really sure what this means in relation to - // STLport's hash_map... they say they "increase the - // bucket count to at least n" -- but does that mean - // their real capacity after resize(n) is more like - // n*2 (since they do linked-list chaining within - // buckets?). - setCapacity(n); - } - - /** - * Size the hash so that it can comfortably contain the given - * number of elements. If the hash already contains more - * elements than new_size, then this may be a no-op. - */ - void setCapacity(int new_size) - { - int new_raw_size = (new_size * 3) / 2; - if (new_raw_size < size()) { return; } - - setRawCapacity(new_raw_size); - } - - /// Behaves much like std::pair. - struct Entry - { - int next_in_chain; // internal chaining for collisions - uint hash_value; // avoids recomputing. Worthwhile? - T key; - U value; - - Entry() : next_in_chain(-2) {} - Entry(const Entry& e) - : next_in_chain(e.next_in_chain), hash_value(e.hash_value), key(e.key), value(e.value) - { - } - Entry(const T& k, const U& v, int next, int hash) - : next_in_chain(next), hash_value(hash), key(k), value(v) - { - } - bool isEmpty() const { return next_in_chain == -2; } - bool isEndOfChain() const { return next_in_chain == -1; } - - void clear() - { - key.~T(); // placement delete - value.~U(); // placement delete - next_in_chain = -2; - } - }; - - - // HashMap enumerator. - typedef int PseudoIndex; - PseudoIndex start() const { PseudoIndex i = 0; findNext(i); return i; } - bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); return i == size_mask+1; }; - void advance(PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); i++; findNext(i); } - - #if NV_CC_GNUC - Entry & operator[]( const PseudoIndex & i ) { - return E(i); - } - const Entry & operator[]( const PseudoIndex & i ) const { - return E(i); - } - #elif NV_CC_MSVC - Entry & operator[]( const PseudoIndexWrapper & i ) { - return E(i(this)); - } - const Entry & operator[]( const PseudoIndexWrapper & i ) const { - return E(i(this)); - } - #endif - - - - private: - - // Find the index of the matching entry. If no match, then return -1. - int findIndex(const T& key) const - { - if (table == NULL) return -1; - - uint hash_value = hash_functor()(key); - int index = hash_value & size_mask; - - const Entry * e = &E(index); - if (e->isEmpty()) return -1; - if (int(e->hash_value & size_mask) != index) return -1; // occupied by a collider - - for (;;) - { - nvCheck((e->hash_value & size_mask) == (hash_value & size_mask)); - - if (e->hash_value == hash_value && e->key == key) - { - // Found it. - return index; - } - nvDebugCheck(! (e->key == key)); // keys are equal, but hash differs! - - // Keep looking through the chain. - index = e->next_in_chain; - if (index == -1) break; // end of chain - - nvCheck(index >= 0 && index <= size_mask); - e = &E(index); - - nvCheck(e->isEmpty() == false); - } - return -1; - } - - // Helpers. - Entry & E(int index) - { - nvDebugCheck(table != NULL); - nvDebugCheck(index >= 0 && index <= size_mask); - return table[index]; - } - const Entry & E(int index) const - { - nvDebugCheck(table != NULL); - nvDebugCheck(index >= 0 && index <= size_mask); - return table[index]; - } - - - /** - * Resize the hash table to the given size (Rehash the - * contents of the current table). The arg is the number of - * hash table entries, not the number of elements we should - * actually contain (which will be less than this). - */ - void setRawCapacity(int new_size) - { - if (new_size <= 0) { - // Special case. - clear(); - return; - } - - // Force new_size to be a power of two. - new_size = nextPowerOfTwo(new_size); - - HashMap new_hash; - new_hash.table = (Entry *) mem::malloc(sizeof(Entry) * new_size); - nvDebugCheck(new_hash.table != NULL); - - new_hash.entry_count = 0; - new_hash.size_mask = new_size - 1; - for (int i = 0; i < new_size; i++) - { - new_hash.E(i).next_in_chain = -2; // mark empty - } - - // Copy stuff to new_hash - if (table != NULL) - { - for (int i = 0, n = size_mask; i <= n; i++) - { - Entry * e = &E(i); - if (e->isEmpty() == false) - { - // Insert old entry into new hash. - new_hash.add(e->key, e->value); - e->clear(); // placement delete of old element - } - } - - // Delete our old data buffer. - mem::free(table); - } - - // Steal new_hash's data. - entry_count = new_hash.entry_count; - size_mask = new_hash.size_mask; - table = new_hash.table; - new_hash.entry_count = 0; - new_hash.size_mask = -1; - new_hash.table = NULL; - } - - // Move the enumerator to the next valid element. - void findNext(PseudoIndex & i) const { - while (i <= size_mask && E(i).isEmpty()) { - i++; - } - } - - - int entry_count; - int size_mask; - Entry * table; - - }; - - - -} // nv namespace - -#endif // NV_CORE_CONTAINER_H diff --git a/src/nvcore/Debug.cpp b/src/nvcore/Debug.cpp index 76390fc..b42782d 100644 --- a/src/nvcore/Debug.cpp +++ b/src/nvcore/Debug.cpp @@ -1,51 +1,51 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio Castaņo #include "Debug.h" #include "StrLib.h" // Extern #if NV_OS_WIN32 //&& NV_CC_MSVC -# define WIN32_LEAN_AND_MEAN -# define VC_EXTRALEAN -# include -# include -# if NV_CC_MSVC -# include -# if _MSC_VER < 1300 -# define DECLSPEC_DEPRECATED - // VC6: change this path to your Platform SDK headers -# include // must be XP version of file -// include "M:\\dev7\\vs\\devtools\\common\\win32sdk\\include\\dbghelp.h" -# else - // VC7: ships with updated headers -# include -# endif -# endif +# define WIN32_LEAN_AND_MEAN +# define VC_EXTRALEAN +# include +# include +# if NV_CC_MSVC +# include +# if _MSC_VER < 1300 +# define DECLSPEC_DEPRECATED +// VC6: change this path to your Platform SDK headers +# include // must be XP version of file +// include "M:\\dev7\\vs\\devtools\\common\\win32sdk\\include\\dbghelp.h" +# else +// VC7: ships with updated headers +# include +# endif +# endif #endif #if !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) -# include +# include #endif #if NV_OS_LINUX && defined(HAVE_EXECINFO_H) -# include // backtrace -# if NV_CC_GNUC // defined(HAVE_CXXABI_H) -# include -# endif +# include // backtrace +# if NV_CC_GNUC // defined(HAVE_CXXABI_H) +# include +# endif #endif #if NV_OS_DARWIN || NV_OS_FREEBSD -# include // getpid -# include -# include // sysctl -# include -# undef HAVE_EXECINFO_H -# if defined(HAVE_EXECINFO_H) // only after OSX 10.5 -# include // backtrace -# if NV_CC_GNUC // defined(HAVE_CXXABI_H) -# include -# endif -# endif +# include // getpid +# include +# include // sysctl +# include +# undef HAVE_EXECINFO_H +# if defined(HAVE_EXECINFO_H) // only after OSX 10.5 +# include // backtrace +# if NV_CC_GNUC // defined(HAVE_CXXABI_H) +# include +# endif +# endif #endif #include // std::runtime_error @@ -56,149 +56,149 @@ using namespace nv; namespace { - static MessageHandler * s_message_handler = NULL; - static AssertHandler * s_assert_handler = NULL; - - static bool s_sig_handler_enabled = false; + static MessageHandler * s_message_handler = NULL; + static AssertHandler * s_assert_handler = NULL; + + static bool s_sig_handler_enabled = false; #if NV_OS_WIN32 && NV_CC_MSVC - // Old exception filter. - static LPTOP_LEVEL_EXCEPTION_FILTER s_old_exception_filter = NULL; + // Old exception filter. + static LPTOP_LEVEL_EXCEPTION_FILTER s_old_exception_filter = NULL; #elif !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) - // Old signal handlers. - struct sigaction s_old_sigsegv; - struct sigaction s_old_sigtrap; - struct sigaction s_old_sigfpe; - struct sigaction s_old_sigbus; - + // Old signal handlers. + struct sigaction s_old_sigsegv; + struct sigaction s_old_sigtrap; + struct sigaction s_old_sigfpe; + struct sigaction s_old_sigbus; + #endif #if NV_OS_WIN32 && NV_CC_MSVC - // TODO write minidump - - static LONG WINAPI nvTopLevelFilter( struct _EXCEPTION_POINTERS * pExceptionInfo) - { - NV_UNUSED(pExceptionInfo); - /* BOOL (WINAPI * Dump) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION ); - - AutoString dbghelp_path(512); - getcwd(dbghelp_path, 512); - dbghelp_path.Append("\\DbgHelp.dll"); - nvTranslatePath(dbghelp_path); - - PiLibrary DbgHelp_lib(dbghelp_path, true); - - if( !DbgHelp_lib.IsValid() ) { - nvDebug("*** 'DbgHelp.dll' not found.\n"); - return EXCEPTION_CONTINUE_SEARCH; - } - - if( !DbgHelp_lib.BindSymbol( (void **)&Dump, "MiniDumpWriteDump" ) ) { - nvDebug("*** 'DbgHelp.dll' too old.\n"); - return EXCEPTION_CONTINUE_SEARCH; - } - - // create the file - HANDLE hFile = ::CreateFile( "nv.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); - if( hFile == INVALID_HANDLE_VALUE ) { - nvDebug("*** Failed to create dump file.\n"); - return EXCEPTION_CONTINUE_SEARCH; - } - - - _MINIDUMP_EXCEPTION_INFORMATION ExInfo; - - ExInfo.ThreadId = ::GetCurrentThreadId(); - ExInfo.ExceptionPointers = pExceptionInfo; - ExInfo.ClientPointers = NULL; - - // write the dump - bool ok = Dump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL )!=0; - ::CloseHandle(hFile); - - if( !ok ) { - nvDebug("*** Failed to save dump file.\n"); - return EXCEPTION_CONTINUE_SEARCH; - } - - nvDebug("--- Dump file saved.\n"); - */ - return EXCEPTION_CONTINUE_SEARCH; - } + // TODO write minidump + + static LONG WINAPI nvTopLevelFilter( struct _EXCEPTION_POINTERS * pExceptionInfo) + { + NV_UNUSED(pExceptionInfo); + /* BOOL (WINAPI * Dump) (HANDLE, DWORD, HANDLE, MINIDUMP_TYPE, PMINIDUMP_EXCEPTION_INFORMATION, PMINIDUMP_USER_STREAM_INFORMATION, PMINIDUMP_CALLBACK_INFORMATION ); + + AutoString dbghelp_path(512); + getcwd(dbghelp_path, 512); + dbghelp_path.Append("\\DbgHelp.dll"); + nvTranslatePath(dbghelp_path); + + PiLibrary DbgHelp_lib(dbghelp_path, true); + + if( !DbgHelp_lib.IsValid() ) { + nvDebug("*** 'DbgHelp.dll' not found.\n"); + return EXCEPTION_CONTINUE_SEARCH; + } + + if( !DbgHelp_lib.BindSymbol( (void **)&Dump, "MiniDumpWriteDump" ) ) { + nvDebug("*** 'DbgHelp.dll' too old.\n"); + return EXCEPTION_CONTINUE_SEARCH; + } + + // create the file + HANDLE hFile = ::CreateFile( "nv.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); + if( hFile == INVALID_HANDLE_VALUE ) { + nvDebug("*** Failed to create dump file.\n"); + return EXCEPTION_CONTINUE_SEARCH; + } + + + _MINIDUMP_EXCEPTION_INFORMATION ExInfo; + + ExInfo.ThreadId = ::GetCurrentThreadId(); + ExInfo.ExceptionPointers = pExceptionInfo; + ExInfo.ClientPointers = NULL; + + // write the dump + bool ok = Dump( GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &ExInfo, NULL, NULL )!=0; + ::CloseHandle(hFile); + + if( !ok ) { + nvDebug("*** Failed to save dump file.\n"); + return EXCEPTION_CONTINUE_SEARCH; + } + + nvDebug("--- Dump file saved.\n"); + */ + return EXCEPTION_CONTINUE_SEARCH; + } #elif !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) // NV_OS_LINUX || NV_OS_DARWIN #if defined(HAVE_EXECINFO_H) // NV_OS_LINUX - static bool nvHasStackTrace() { + static bool nvHasStackTrace() { #if NV_OS_DARWIN - return backtrace != NULL; + return backtrace != NULL; #else - return true; + return true; #endif - } + } - static void nvPrintStackTrace(void * trace[], int size, int start=0) { - char ** string_array = backtrace_symbols(trace, size); - - nvDebug( "\nDumping stacktrace:\n" ); - for(int i = start; i < size-1; i++ ) { -# if NV_CC_GNUC // defined(HAVE_CXXABI_H) - char * begin = strchr(string_array[i], '('); - char * end = strchr(string_array[i], '+'); - if( begin != 0 && begin < end ) { - int stat; - *end = '\0'; - *begin = '\0'; - char * module = string_array[i]; - char * name = abi::__cxa_demangle(begin+1, 0, 0, &stat); - if( name == NULL || begin[1] != '_' || begin[2] != 'Z' ) { - nvDebug( " In: [%s] '%s'\n", module, begin+1 ); - } - else { - nvDebug( " In: [%s] '%s'\n", module, name ); - } - free(name); - } - else { - nvDebug( " In: '%s'\n", string_array[i] ); - } -# else - nvDebug( " In: '%s'\n", string_array[i] ); -# endif - } - nvDebug("\n"); - - free(string_array); - } + static void nvPrintStackTrace(void * trace[], int size, int start=0) { + char ** string_array = backtrace_symbols(trace, size); + + nvDebug( "\nDumping stacktrace:\n" ); + for(int i = start; i < size-1; i++ ) { +# if NV_CC_GNUC // defined(HAVE_CXXABI_H) + char * begin = strchr(string_array[i], '('); + char * end = strchr(string_array[i], '+'); + if( begin != 0 && begin < end ) { + int stat; + *end = '\0'; + *begin = '\0'; + char * module = string_array[i]; + char * name = abi::__cxa_demangle(begin+1, 0, 0, &stat); + if( name == NULL || begin[1] != '_' || begin[2] != 'Z' ) { + nvDebug( " In: [%s] '%s'\n", module, begin+1 ); + } + else { + nvDebug( " In: [%s] '%s'\n", module, name ); + } + free(name); + } + else { + nvDebug( " In: '%s'\n", string_array[i] ); + } +# else + nvDebug( " In: '%s'\n", string_array[i] ); +# endif + } + nvDebug("\n"); + + free(string_array); + } #endif // defined(HAVE_EXECINFO_H) - static void * callerAddress(void * secret) - { -# if NV_OS_DARWIN -# if defined(_STRUCT_MCONTEXT) -# if NV_CPU_PPC - ucontext_t * ucp = (ucontext_t *)secret; - return (void *) ucp->uc_mcontext->__ss.__srr0; -# elif NV_CPU_X86 - ucontext_t * ucp = (ucontext_t *)secret; - return (void *) ucp->uc_mcontext->__ss.__eip; -# endif -# else -# if NV_CPU_PPC - ucontext_t * ucp = (ucontext_t *)secret; - return (void *) ucp->uc_mcontext->ss.srr0; -# elif NV_CPU_X86 - ucontext_t * ucp = (ucontext_t *)secret; - return (void *) ucp->uc_mcontext->ss.eip; -# endif -# endif + static void * callerAddress(void * secret) + { +#if NV_OS_DARWIN +# if defined(_STRUCT_MCONTEXT) +# if NV_CPU_PPC + ucontext_t * ucp = (ucontext_t *)secret; + return (void *) ucp->uc_mcontext->__ss.__srr0; +# elif NV_CPU_X86 + ucontext_t * ucp = (ucontext_t *)secret; + return (void *) ucp->uc_mcontext->__ss.__eip; +# endif +# else +# if NV_CPU_PPC + ucontext_t * ucp = (ucontext_t *)secret; + return (void *) ucp->uc_mcontext->ss.srr0; +# elif NV_CPU_X86 + ucontext_t * ucp = (ucontext_t *)secret; + return (void *) ucp->uc_mcontext->ss.eip; +# endif +# endif # elif NV_OS_FREEBSD # if NV_CPU_X86_64 ucontext_t * ucp = (ucontext_t *)secret; @@ -207,253 +207,249 @@ namespace ucontext_t * ucp = (ucontext_t *)secret; return (void *)ucp->uc_mcontext.mc_eip; # endif -# else -# if NV_CPU_X86_64 - // #define REG_RIP REG_INDEX(rip) // seems to be 16 - ucontext_t * ucp = (ucontext_t *)secret; - return (void *)ucp->uc_mcontext.gregs[REG_RIP]; -# elif NV_CPU_X86 - ucontext_t * ucp = (ucontext_t *)secret; - return (void *)ucp->uc_mcontext.gregs[14/*REG_EIP*/]; -# elif NV_CPU_PPC - ucontext_t * ucp = (ucontext_t *)secret; - return (void *) ucp->uc_mcontext.regs->nip; -# endif -# endif - - // How to obtain the instruction pointers in different platforms, from mlton's source code. - // http://mlton.org/ - // OpenBSD && NetBSD - // ucp->sc_eip - // FreeBSD: - // ucp->uc_mcontext.mc_eip - // HPUX: - // ucp->uc_link - // Solaris: - // ucp->uc_mcontext.gregs[REG_PC] - // Linux hppa: - // uc->uc_mcontext.sc_iaoq[0] & ~0x3UL - // Linux sparc: - // ((struct sigcontext*) secret)->sigc_regs.tpc - // Linux sparc64: - // ((struct sigcontext*) secret)->si_regs.pc - - // potentially correct for other archs: - // Linux alpha: ucp->m_context.sc_pc - // Linux arm: ucp->m_context.ctx.arm_pc - // Linux ia64: ucp->m_context.sc_ip & ~0x3UL - // Linux mips: ucp->m_context.sc_pc - // Linux s390: ucp->m_context.sregs->regs.psw.addr - } - - static void nvSigHandler(int sig, siginfo_t *info, void *secret) - { - void * pnt = callerAddress(secret); - - // Do something useful with siginfo_t - if (sig == SIGSEGV) { - if (pnt != NULL) nvDebug("Got signal %d, faulty address is %p, from %p\n", sig, info->si_addr, pnt); - else nvDebug("Got signal %d, faulty address is %p\n", sig, info->si_addr); - } - else if(sig == SIGTRAP) { - nvDebug("Breakpoint hit.\n"); - } - else { - nvDebug("Got signal %d\n", sig); - } - -# if defined(HAVE_EXECINFO_H) - if (nvHasStackTrace()) // in case of weak linking - { - void * trace[64]; - int size = backtrace(trace, 64); - - if (pnt != NULL) { - // Overwrite sigaction with caller's address. - trace[1] = pnt; - } - - nvPrintStackTrace(trace, size, 1); - } -# endif // defined(HAVE_EXECINFO_H) - - exit(0); - } +#else +# if NV_CPU_X86_64 + // #define REG_RIP REG_INDEX(rip) // seems to be 16 + ucontext_t * ucp = (ucontext_t *)secret; + return (void *)ucp->uc_mcontext.gregs[REG_RIP]; +# elif NV_CPU_X86 + ucontext_t * ucp = (ucontext_t *)secret; + return (void *)ucp->uc_mcontext.gregs[14/*REG_EIP*/]; +# elif NV_CPU_PPC + ucontext_t * ucp = (ucontext_t *)secret; + return (void *) ucp->uc_mcontext.regs->nip; +# endif +#endif + + // How to obtain the instruction pointers in different platforms, from mlton's source code. + // http://mlton.org/ + // OpenBSD && NetBSD + // ucp->sc_eip + // FreeBSD: + // ucp->uc_mcontext.mc_eip + // HPUX: + // ucp->uc_link + // Solaris: + // ucp->uc_mcontext.gregs[REG_PC] + // Linux hppa: + // uc->uc_mcontext.sc_iaoq[0] & ~0x3UL + // Linux sparc: + // ((struct sigcontext*) secret)->sigc_regs.tpc + // Linux sparc64: + // ((struct sigcontext*) secret)->si_regs.pc + + // potentially correct for other archs: + // Linux alpha: ucp->m_context.sc_pc + // Linux arm: ucp->m_context.ctx.arm_pc + // Linux ia64: ucp->m_context.sc_ip & ~0x3UL + // Linux mips: ucp->m_context.sc_pc + // Linux s390: ucp->m_context.sregs->regs.psw.addr + } + + static void nvSigHandler(int sig, siginfo_t *info, void *secret) + { + void * pnt = callerAddress(secret); + + // Do something useful with siginfo_t + if (sig == SIGSEGV) { + if (pnt != NULL) nvDebug("Got signal %d, faulty address is %p, from %p\n", sig, info->si_addr, pnt); + else nvDebug("Got signal %d, faulty address is %p\n", sig, info->si_addr); + } + else if(sig == SIGTRAP) { + nvDebug("Breakpoint hit.\n"); + } + else { + nvDebug("Got signal %d\n", sig); + } + +#if defined(HAVE_EXECINFO_H) + if (nvHasStackTrace()) // in case of weak linking + { + void * trace[64]; + int size = backtrace(trace, 64); + + if (pnt != NULL) { + // Overwrite sigaction with caller's address. + trace[1] = pnt; + } + + nvPrintStackTrace(trace, size, 1); + } +#endif // defined(HAVE_EXECINFO_H) + + exit(0); + } #endif // defined(HAVE_SIGNAL_H) #if NV_OS_WIN32 //&& NV_CC_MSVC - - /** Win32 asset handler. */ - struct Win32AssertHandler : public AssertHandler - { - // Code from Daniel Vogel. - static bool isDebuggerPresent() - { - bool result = false; - - HINSTANCE kern_lib = LoadLibraryExA( "kernel32.dll", NULL, 0 ); - if( kern_lib ) { - FARPROC lIsDebuggerPresent = GetProcAddress( kern_lib, "IsDebuggerPresent" ); - if( lIsDebuggerPresent && lIsDebuggerPresent() ) { - result = true; - } - - FreeLibrary( kern_lib ); - } - return result; - } - - // Flush the message queue. This is necessary for the message box to show up. - static void flushMessageQueue() - { - MSG msg; - while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { - if( msg.message == WM_QUIT ) break; - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - } - - // Assert handler method. - virtual int assert( const char * exp, const char * file, int line, const char * func/*=NULL*/ ) - { - 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 ); - nvDebug( error_string ); - } - else { - error_string.format( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line ); - nvDebug( error_string ); - } - - #if _DEBUG - - if( isDebuggerPresent() ) { - return NV_ABORT_DEBUG; - } - - flushMessageQueue(); - int action = MessageBoxA(NULL, error_string, "Assertion failed", MB_ABORTRETRYIGNORE|MB_ICONERROR); - switch( action ) { - case IDRETRY: - ret = NV_ABORT_DEBUG; - break; - case IDIGNORE: - ret = NV_ABORT_IGNORE; - break; - case IDABORT: - default: - ret = NV_ABORT_EXIT; - break; - } - /*if( _CrtDbgReport( _CRT_ASSERT, file, line, module, exp ) == 1 ) { - return NV_ABORT_DEBUG; - }*/ - - #endif - - if( ret == NV_ABORT_EXIT ) { - // Exit cleanly. - throw std::runtime_error("Assertion failed"); - } - - return ret; - } - }; - + + /** Win32 asset handler. */ + struct Win32AssertHandler : public AssertHandler + { + // Code from Daniel Vogel. + static bool isDebuggerPresent() + { + bool result = false; + + HINSTANCE kern_lib = LoadLibraryExA( "kernel32.dll", NULL, 0 ); + if( kern_lib ) { + FARPROC lIsDebuggerPresent = GetProcAddress( kern_lib, "IsDebuggerPresent" ); + if( lIsDebuggerPresent && lIsDebuggerPresent() ) { + result = true; + } + + FreeLibrary( kern_lib ); + } + return result; + } + + // Flush the message queue. This is necessary for the message box to show up. + static void flushMessageQueue() + { + MSG msg; + while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) { + if( msg.message == WM_QUIT ) break; + TranslateMessage( &msg ); + DispatchMessage( &msg ); + } + } + + // Assert handler method. + virtual int assertion( const char * exp, const char * file, int line, const char * func/*=NULL*/ ) + { + 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 ); + nvDebug( error_string ); + } + else { + error_string.format( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line ); + nvDebug( error_string ); + } + + if (isDebuggerPresent()) { + return NV_ABORT_DEBUG; + } + + flushMessageQueue(); + int action = MessageBoxA(NULL, error_string, "Assertion failed", MB_ABORTRETRYIGNORE|MB_ICONERROR); + switch( action ) { + case IDRETRY: + ret = NV_ABORT_DEBUG; + break; + case IDIGNORE: + ret = NV_ABORT_IGNORE; + break; + case IDABORT: + default: + ret = NV_ABORT_EXIT; + break; + } + /*if( _CrtDbgReport( _CRT_ASSERT, file, line, module, exp ) == 1 ) { + return NV_ABORT_DEBUG; + }*/ + + if( ret == NV_ABORT_EXIT ) { + // Exit cleanly. + throw std::runtime_error("Assertion failed"); + } + + return ret; + } + }; + #else - - /** Unix asset handler. */ - struct UnixAssertHandler : public AssertHandler - { - bool isDebuggerPresent() - { -# if NV_OS_DARWIN - int mib[4]; - struct kinfo_proc info; - size_t size; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - size = sizeof(info); - info.kp_proc.p_flag = 0; - sysctl(mib,4,&info,&size,NULL,0); - return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED); -# else - // if ppid != sid, some process spawned our app, probably a debugger. - return getsid(getpid()) != getppid(); -# endif - } - - // Assert handler method. - virtual int assert(const char * exp, const char * file, int line, const char * func) - { - 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 ); - } - -# if _DEBUG - if( isDebuggerPresent() ) { - return NV_ABORT_DEBUG; - } -# endif -# if defined(HAVE_EXECINFO_H) - if (nvHasStackTrace()) - { - void * trace[64]; - int size = backtrace(trace, 64); - nvPrintStackTrace(trace, size, 2); - } -# endif + /** Unix asset handler. */ + struct UnixAssertHandler : public AssertHandler + { + bool isDebuggerPresent() + { +#if NV_OS_DARWIN + int mib[4]; + struct kinfo_proc info; + size_t size; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + size = sizeof(info); + info.kp_proc.p_flag = 0; + sysctl(mib,4,&info,&size,NULL,0); + return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED); +#else + // if ppid != sid, some process spawned our app, probably a debugger. + return getsid(getpid()) != getppid(); +#endif + } + + // Assert handler method. + virtual int assertion(const char * exp, const char * file, int line, const char * func) + { + 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 ); + } + +#if _DEBUG + if (isDebuggerPresent()) { + return NV_ABORT_DEBUG; + } +#endif + +#if defined(HAVE_EXECINFO_H) + if (nvHasStackTrace()) + { + void * trace[64]; + int size = backtrace(trace, 64); + nvPrintStackTrace(trace, size, 2); + } +#endif + + // Exit cleanly. + throw std::runtime_error("Assertion failed"); + } + }; - // Exit cleanly. - throw std::runtime_error("Assertion failed"); - } - }; - #endif } // namespace /// Handle assertion through the asset handler. -int nvAbort(const char * exp, const char * file, int line, const char * func) +int nvAbort(const char * exp, const char * file, int line, const char * func/*=NULL*/) { #if NV_OS_WIN32 //&& NV_CC_MSVC - static Win32AssertHandler s_default_assert_handler; + static Win32AssertHandler s_default_assert_handler; #else - static UnixAssertHandler s_default_assert_handler; + static UnixAssertHandler s_default_assert_handler; #endif - - if( s_assert_handler != NULL ) { - return s_assert_handler->assert( exp, file, line, func ); - } - else { - return s_default_assert_handler.assert( exp, file, line, func ); - } + + 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 ); + } } /// Shows a message through the message handler. -void NV_CDECL nvDebug(const char *msg, ...) +void NV_CDECL nvDebugPrint(const char *msg, ...) { - va_list arg; - va_start(arg,msg); - if( s_message_handler != NULL ) { - s_message_handler->log( msg, arg ); - } - va_end(arg); + va_list arg; + va_start(arg,msg); + if (s_message_handler != NULL) { + s_message_handler->log( msg, arg ); + } + va_end(arg); } @@ -461,12 +457,12 @@ void NV_CDECL nvDebug(const char *msg, ...) void debug::dumpInfo() { #if !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) && defined(HAVE_EXECINFO_H) - if (nvHasStackTrace()) - { - void * trace[64]; - int size = backtrace(trace, 64); - nvPrintStackTrace(trace, size, 1); - } + if (nvHasStackTrace()) + { + void * trace[64]; + int size = backtrace(trace, 64); + nvPrintStackTrace(trace, size, 1); + } #endif } @@ -474,72 +470,72 @@ void debug::dumpInfo() /// Set the debug message handler. void debug::setMessageHandler(MessageHandler * message_handler) { - s_message_handler = message_handler; + s_message_handler = message_handler; } /// Reset the debug message handler. void debug::resetMessageHandler() { - s_message_handler = NULL; + s_message_handler = NULL; } /// Set the assert handler. void debug::setAssertHandler(AssertHandler * assert_handler) { - s_assert_handler = assert_handler; + s_assert_handler = assert_handler; } /// Reset the assert handler. void debug::resetAssertHandler() { - s_assert_handler = NULL; + s_assert_handler = NULL; } /// Enable signal handler. void debug::enableSigHandler() { - nvCheck(s_sig_handler_enabled != true); - s_sig_handler_enabled = true; - -#if NV_OS_WIN32 && NV_CC_MSVC - - s_old_exception_filter = ::SetUnhandledExceptionFilter( nvTopLevelFilter ); - -#elif !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) - - // Install our signal handler - struct sigaction sa; - sa.sa_sigaction = nvSigHandler; - sigemptyset (&sa.sa_mask); - sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; + nvCheck(s_sig_handler_enabled != true); + s_sig_handler_enabled = true; + +#if NV_OS_WIN32 && NV_CC_MSVC + + s_old_exception_filter = ::SetUnhandledExceptionFilter( nvTopLevelFilter ); + +#elif !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) + + // Install our signal handler + struct sigaction sa; + sa.sa_sigaction = nvSigHandler; + sigemptyset (&sa.sa_mask); + sa.sa_flags = SA_ONSTACK | SA_RESTART | SA_SIGINFO; + + sigaction(SIGSEGV, &sa, &s_old_sigsegv); + sigaction(SIGTRAP, &sa, &s_old_sigtrap); + sigaction(SIGFPE, &sa, &s_old_sigfpe); + sigaction(SIGBUS, &sa, &s_old_sigbus); - sigaction(SIGSEGV, &sa, &s_old_sigsegv); - sigaction(SIGTRAP, &sa, &s_old_sigtrap); - sigaction(SIGFPE, &sa, &s_old_sigfpe); - sigaction(SIGBUS, &sa, &s_old_sigbus); - #endif } /// Disable signal handler. void debug::disableSigHandler() { - nvCheck(s_sig_handler_enabled == true); - s_sig_handler_enabled = false; + nvCheck(s_sig_handler_enabled == true); + s_sig_handler_enabled = false; #if NV_OS_WIN32 && NV_CC_MSVC - ::SetUnhandledExceptionFilter( s_old_exception_filter ); - s_old_exception_filter = NULL; + ::SetUnhandledExceptionFilter( s_old_exception_filter ); + s_old_exception_filter = NULL; #elif !NV_OS_WIN32 && defined(HAVE_SIGNAL_H) - - sigaction(SIGSEGV, &s_old_sigsegv, NULL); - sigaction(SIGTRAP, &s_old_sigtrap, NULL); - sigaction(SIGFPE, &s_old_sigfpe, NULL); - sigaction(SIGBUS, &s_old_sigbus, NULL); - + + sigaction(SIGSEGV, &s_old_sigsegv, NULL); + sigaction(SIGTRAP, &s_old_sigtrap, NULL); + sigaction(SIGFPE, &s_old_sigfpe, NULL); + sigaction(SIGBUS, &s_old_sigbus, NULL); + #endif } diff --git a/src/nvcore/Debug.h b/src/nvcore/Debug.h index 3935211..d188689 100644 --- a/src/nvcore/Debug.h +++ b/src/nvcore/Debug.h @@ -1,131 +1,173 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio Castaņo +#pragma once #ifndef NV_CORE_DEBUG_H #define NV_CORE_DEBUG_H #include "nvcore.h" #if defined(HAVE_STDARG_H) -# include // va_list +# include // va_list #endif -#define NV_ABORT_DEBUG 1 -#define NV_ABORT_IGNORE 2 -#define NV_ABORT_EXIT 3 - -#undef assert // avoid conflicts with assert method. +#define NV_ABORT_DEBUG 1 +#define NV_ABORT_IGNORE 2 +#define NV_ABORT_EXIT 3 #define nvNoAssert(exp) \ - do { \ - (void)sizeof(exp); \ - } while(0) + do { \ + (void)sizeof(exp); \ + } while(0) #if NV_NO_ASSERT -# define nvAssert(exp) nvNoAssert(exp) -# define nvCheck(exp) nvNoAssert(exp) -# define nvDebugAssert(exp) nvNoAssert(exp) -# define nvDebugCheck(exp) nvNoAssert(exp) -# define nvDebugBreak() nvNoAssert(0) +# define nvAssert(exp) nvNoAssert(exp) +# define nvCheck(exp) nvNoAssert(exp) +# define nvDebugAssert(exp) nvNoAssert(exp) +# define nvDebugCheck(exp) nvNoAssert(exp) +# define nvDebugBreak() nvNoAssert(0) #else // NV_NO_ASSERT -# if NV_CC_MSVC - // @@ Does this work in msvc-6 and earlier? - // @@ Do I have to include ? -# define nvDebugBreak() __debugbreak() - // define nvDebugBreak() __asm int 3 -# elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN -# define nvDebugBreak() __asm__ volatile ("trap"); -# elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN -# define nvDebugBreak() __asm__ volatile ("int3"); -# elif NV_CC_GNUC && NV_CPU_X86 -# define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) ) -# else -# include -# define nvDebugBreak() raise(SIGTRAP); - // define nvDebugBreak() *((int *)(0)) = 0 -# endif +# if NV_CC_MSVC +// @@ Does this work in msvc-6 and earlier? +# define nvDebugBreak() __debugbreak() +//# define nvDebugBreak() __asm { int 3 } +# elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN +// @@ Use __builtin_trap() on GCC +# define nvDebugBreak() __asm__ volatile ("trap"); +# elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN +# define nvDebugBreak() __asm__ volatile ("int3"); +# elif NV_CC_GNUC && NV_CPU_X86 +# define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) ) +# else +# include +# define nvDebugBreak() raise(SIGTRAP); +// define nvDebugBreak() *((int *)(0)) = 0 +# endif -# define nvAssertMacro(exp) \ - do { \ - if(!(exp)) { \ - if( nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG ) { \ - nvDebugBreak(); \ - } \ - } \ - } while(false) +#define nvDebugBreakOnce() \ + do { \ + static bool firstTime = true; \ + if (firstTime) { firstTime = false; nvDebugBreak(); } \ + } while(false) -# define nvAssert(exp) nvAssertMacro(exp) -# define nvCheck(exp) nvAssertMacro(exp) +# define nvAssertMacro(exp) \ + do { \ + if (!(exp)) { \ + if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \ + nvDebugBreak(); \ + } \ + } \ + } while(false) -# 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 +# define nvAssertMacroWithIgnoreAll(exp) \ + do { \ + static bool ignoreAll = false; \ + if (!ignoreAll && !(exp)) { \ + if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \ + nvDebugBreak(); \ + } else { \ + ignoreAll = true; \ + } \ + } \ + } while(false) + +# 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 #endif // NV_NO_ASSERT // Use nvAssume for very simple expresions only: nvAssume(0), nvAssume(value == true), etc. -#if defined(_DEBUG) -# if NV_CC_MSVC -# define nvAssume(exp) __assume(exp) -# else -# define nvAssume(exp) nvCheck(exp) -# endif +#if !defined(_DEBUG) +# if NV_CC_MSVC +# define nvAssume(exp) __assume(exp) +# else +# define nvAssume(exp) nvCheck(exp) +# endif #else -# define nvAssume(exp) nvCheck(exp) +# define nvAssume(exp) nvCheck(exp) #endif -#define nvError(x) nvAbort(x, __FILE__, __LINE__, __FUNC__) -#define nvWarning(x) nvDebug("*** Warning %s/%d: %s\n", __FILE__, __LINE__, (x)) +#define nvError(x) nvAbort(x, __FILE__, __LINE__, __FUNC__) +#define nvWarning(x) nvDebugPrint("*** Warning %s/%d: %s\n", __FILE__, __LINE__, (x)) - -#if PI_CC_MSVC -// @@ I'm not sure it's a good idea to use the default static assert. -# define nvStaticCheck(x) _STATIC_ASSERT(x) -#else -# define nvStaticCheck(x) typedef char NV_DO_STRING_JOIN2(__static_assert_,__LINE__)[(x)] -// define nvStaticCheck(x) switch(0) { case 0: case x:; } +#ifndef NV_DEBUG_PRINT +#define NV_DEBUG_PRINT 1 //defined(_DEBUG) #endif -NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = 0); -NVCORE_API void NV_CDECL nvDebug( const char *msg, ... ) __attribute__((format (printf, 1, 2))); +#if NV_DEBUG_PRINT +#define nvDebug(...) nvDebugPrint(__VA_ARGS__) +#else +#if NV_CC_MSVC +#define nvDebug(...) __noop(__VA_ARGS__) +#else +#define nvDebug(...) ((void)0) // Non-msvc platforms do not evaluate arguments? +#endif +#endif + + +#if __cplusplus > 199711L +#define nvStaticCheck(x) static_assert(x) +#else +#define nvStaticCheck(x) typedef char NV_DO_STRING_JOIN2(__static_assert_,__LINE__)[(x)] +#endif + +NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = NULL); +NVCORE_API void NV_CDECL nvDebugPrint( const char *msg, ... ) __attribute__((format (printf, 1, 2))); namespace nv { - /** Message handler interface. */ - struct MessageHandler { - virtual void log(const char * str, va_list arg) = 0; - virtual ~MessageHandler() {} - }; - - /** Assert handler interface. */ - struct AssertHandler { - virtual int assert(const char *exp, const char *file, int line, const char *func = 0) = 0; - virtual ~AssertHandler() {} - }; + inline bool isValidPtr(const void * ptr) { + #if NV_CPU_X86_64 + if (ptr == NULL) return true; + if (reinterpret_cast(ptr) < 0x10000ULL) return false; + if (reinterpret_cast(ptr) >= 0x000007FFFFFEFFFFULL) return false; + #else + if (reinterpret_cast(ptr) == 0xcccccccc) return false; + if (reinterpret_cast(ptr) == 0xcdcdcdcd) return false; + if (reinterpret_cast(ptr) == 0xdddddddd) return false; + if (reinterpret_cast(ptr) == 0xffffffff) return false; + #endif + return true; + } + + /// Message handler interface. + struct MessageHandler { + virtual void log(const char * str, va_list arg) = 0; + virtual ~MessageHandler() {} + }; + + /// Assert handler interface. + struct AssertHandler { + virtual int assertion(const char *exp, const char *file, int line, const char *func = NULL) = 0; + virtual ~AssertHandler() {} + }; - namespace debug - { - NVCORE_API void dumpInfo(); - - // These functions are not thread safe. - NVCORE_API void setMessageHandler( MessageHandler * messageHandler ); - NVCORE_API void resetMessageHandler(); - - NVCORE_API void setAssertHandler( AssertHandler * assertHanlder ); - NVCORE_API void resetAssertHandler(); - - NVCORE_API void enableSigHandler(); - NVCORE_API void disableSigHandler(); - } + namespace debug + { + NVCORE_API void dumpInfo(); + + NVCORE_API void setMessageHandler( MessageHandler * messageHandler ); + NVCORE_API void resetMessageHandler(); + + NVCORE_API void setAssertHandler( AssertHandler * assertHanlder ); + NVCORE_API void resetAssertHandler(); + + NVCORE_API void enableSigHandler(); + NVCORE_API void disableSigHandler(); + } } // nv namespace -#endif // NV_CORE_DEBUG_H +#endif // NV_CORE_DEBUG_H diff --git a/src/nvcore/DefsVcWin32.h b/src/nvcore/DefsVcWin32.h index c1b6d36..a342ccc 100644 --- a/src/nvcore/DefsVcWin32.h +++ b/src/nvcore/DefsVcWin32.h @@ -1,3 +1,5 @@ +// This code is in the public domain -- Ignacio Castaņo + #ifndef NV_CORE_H #error "Do not include this file directly." #endif @@ -20,13 +22,15 @@ // Set standard function names. #define snprintf _snprintf #if _MSC_VER < 1500 -# define vsnprintf _vsnprintf +# define vsnprintf _vsnprintf #endif #define vsscanf _vsscanf #define chdir _chdir #define getcwd _getcwd -#define va_copy(a, b) a = b +#ifndef va_copy +#define va_copy(a, b) (a) = (b) +#endif #if !defined restrict #define restrict @@ -59,20 +63,20 @@ typedef uint32 uint; // Unwanted VC++ warnings to disable. /* -#pragma warning(disable : 4244) // conversion to float, possible loss of data -#pragma warning(disable : 4245) // conversion from 'enum ' to 'unsigned long', signed/unsigned mismatch -#pragma warning(disable : 4100) // unreferenced formal parameter -#pragma warning(disable : 4514) // unreferenced inline function has been removed -#pragma warning(disable : 4710) // inline function not expanded -#pragma warning(disable : 4127) // Conditional expression is constant -#pragma warning(disable : 4305) // truncation from 'const double' to 'float' -#pragma warning(disable : 4505) // unreferenced local function has been removed +#pragma warning(disable : 4244) // conversion to float, possible loss of data +#pragma warning(disable : 4245) // conversion from 'enum ' to 'unsigned long', signed/unsigned mismatch +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#pragma warning(disable : 4710) // inline function not expanded +#pragma warning(disable : 4127) // Conditional expression is constant +#pragma warning(disable : 4305) // truncation from 'const double' to 'float' +#pragma warning(disable : 4505) // unreferenced local function has been removed -#pragma warning(disable : 4702) // unreachable code in inline expanded function -#pragma warning(disable : 4711) // function selected for automatic inlining -#pragma warning(disable : 4725) // Pentium fdiv bug +#pragma warning(disable : 4702) // unreachable code in inline expanded function +#pragma warning(disable : 4711) // function selected for automatic inlining +#pragma warning(disable : 4725) // Pentium fdiv bug -#pragma warning(disable : 4786) // Identifier was truncated and cannot be debugged. +#pragma warning(disable : 4786) // Identifier was truncated and cannot be debugged. -#pragma warning(disable : 4675) // resolved overload was found by argument-dependent lookup +#pragma warning(disable : 4675) // resolved overload was found by argument-dependent lookup */ diff --git a/src/nvcore/FileSystem.cpp b/src/nvcore/FileSystem.cpp index 4c50887..f58034c 100644 --- a/src/nvcore/FileSystem.cpp +++ b/src/nvcore/FileSystem.cpp @@ -1,13 +1,13 @@ // This code is in the public domain -- castano@gmail.com #include "FileSystem.h" -#include #if NV_OS_WIN32 #define _CRT_NONSTDC_NO_WARNINGS // _chdir is defined deprecated, but that's a bug, chdir is deprecated, _chdir is *not*. //#include // PathFileExists #include // GetFileAttributes #include // _mkdir +#include // remove, unlink #else #include #include @@ -26,7 +26,7 @@ bool FileSystem::exists(const char * path) #elif NV_OS_WIN32 // PathFileExists requires linking to shlwapi.lib //return PathFileExists(path) != 0; - return GetFileAttributes(path) != 0xFFFFFFFF; + return GetFileAttributesA(path) != 0xFFFFFFFF; #else if (FILE * fp = fopen(path, "r")) { @@ -53,4 +53,10 @@ bool FileSystem::changeDirectory(const char * path) #else return chdir(path) != -1; #endif +} + +bool FileSystem::removeFile(const char * path) +{ + // @@ Use unlink or remove? + return remove(path) == 0; } \ No newline at end of file diff --git a/src/nvcore/FileSystem.h b/src/nvcore/FileSystem.h index 97447ca..f0f06aa 100644 --- a/src/nvcore/FileSystem.h +++ b/src/nvcore/FileSystem.h @@ -1,5 +1,6 @@ // This code is in the public domain -- castano@gmail.com +#pragma once #ifndef NV_CORE_FILESYSTEM_H #define NV_CORE_FILESYSTEM_H @@ -8,14 +9,14 @@ namespace nv { - namespace FileSystem - { + namespace FileSystem + { + NVCORE_API bool exists(const char * path); + NVCORE_API bool createDirectory(const char * path); + NVCORE_API bool changeDirectory(const char * path); + NVCORE_API bool removeFile(const char * path); - NVCORE_API bool exists(const char * path); - NVCORE_API bool createDirectory(const char * path); - NVCORE_API bool changeDirectory(const char * path); - - } // FileSystem namespace + } // FileSystem namespace } // nv namespace diff --git a/src/nvcore/HashMap.h b/src/nvcore/HashMap.h new file mode 100644 index 0000000..15eb4ad --- /dev/null +++ b/src/nvcore/HashMap.h @@ -0,0 +1,563 @@ +// This code is in the public domain -- Ignacio Castaņo + +#pragma once +#ifndef NV_CORE_HASHMAP_H +#define NV_CORE_HASHMAP_H + +/* +HashMap based on Thatcher Ulrich container, donated to the Public Domain. +*/ + + +#include "nvcore.h" +#include "Memory.h" +#include "Debug.h" +#include "Stream.h" +#include "Utils.h" // hash +#include "Array.h" // foreach/pseudoindex + +#include // for placement new + + +namespace nv +{ + /** Thatcher Ulrich's hash table. + * + * Hash table, linear probing, internal chaining. One + * interesting/nice thing about this implementation is that the table + * itself is a flat chunk of memory containing no pointers, only + * relative indices. If the key and value types of the hash contain + * no pointers, then the hash can be serialized using raw IO. Could + * come in handy. + * + * Never shrinks, unless you explicitly clear() it. Expands on + * demand, though. For best results, if you know roughly how big your + * table will be, default it to that size when you create it. + */ + template, typename E = Equal > + class NVCORE_CLASS HashMap + { + NV_FORBID_COPY(HashMap) + public: + + /// Default ctor. + HashMap() : entry_count(0), size_mask(-1), table(NULL) { } + + /// Ctor with size hint. + explicit HashMap(int size_hint) : entry_count(0), size_mask(-1), table(NULL) { setCapacity(size_hint); } + + /// Dtor. + ~HashMap() { clear(); } + + + /// Set a new or existing value under the key, to the value. + void set(const T& key, const U& value) + { + int index = findIndex(key); + if (index >= 0) + { + entry(index).value = value; + return; + } + + // Entry under key doesn't exist. + add(key, value); + } + + + /// Add a new value to the hash table, under the specified key. + void add(const T& key, const U& value) + { + nvCheck(findIndex(key) == -1); + + checkExpand(); + nvCheck(table != NULL); + entry_count++; + + const uint hash_value = compute_hash(key); + const int index = hash_value & size_mask; + + Entry * natural_entry = &(entry(index)); + + if (natural_entry->isEmpty()) + { + // Put the new entry in. + new (natural_entry) Entry(key, value, -1, hash_value); + } + else if (natural_entry->isTombstone()) { + // Put the new entry in, without disturbing the rest of the chain. + int next_in_chain = natural_entry->next_in_chain; + new (natural_entry) Entry(key, value, next_in_chain, hash_value); + } + else + { + // Find a blank spot. + int blank_index = index; + for (int search_count = 0; ; search_count++) + { + blank_index = (blank_index + 1) & size_mask; + if (entry(blank_index).isEmpty()) break; // found it + if (entry(blank_index).isTombstone()) { + blank_index = removeTombstone(blank_index); + break; + } + nvCheck(search_count < this->size_mask); + } + Entry * blank_entry = &entry(blank_index); + + if (int(natural_entry->hash_value & size_mask) == index) + { + // Collision. Link into this chain. + + // Move existing list head. + new (blank_entry) Entry(*natural_entry); // placement new, copy ctor + + // Put the new info in the natural entry. + natural_entry->key = key; + natural_entry->value = value; + natural_entry->next_in_chain = blank_index; + natural_entry->hash_value = hash_value; + } + else + { + // Existing entry does not naturally + // belong in this slot. Existing + // entry must be moved. + + // Find natural location of collided element (i.e. root of chain) + int collided_index = natural_entry->hash_value & size_mask; + for (int search_count = 0; ; search_count++) + { + Entry * e = &entry(collided_index); + if (e->next_in_chain == index) + { + // Here's where we need to splice. + new (blank_entry) Entry(*natural_entry); + e->next_in_chain = blank_index; + break; + } + collided_index = e->next_in_chain; + nvCheck(collided_index >= 0 && collided_index <= size_mask); + nvCheck(search_count <= size_mask); + } + + // Put the new data in the natural entry. + natural_entry->key = key; + natural_entry->value = value; + natural_entry->hash_value = hash_value; + natural_entry->next_in_chain = -1; + } + } + } + + + /// Remove the first value under the specified key. + bool remove(const T& key) + { + if (table == NULL) + { + return false; + } + + int index = findIndex(key); + if (index < 0) + { + return false; + } + + Entry * pos = &entry(index); + + int natural_index = (int) (pos->hash_value & size_mask); + + if (index != natural_index) { + // We're not the head of our chain, so we can + // be spliced out of it. + + // Iterate up the chain, and splice out when + // we get to m_index. + Entry* e = &entry(natural_index); + while (e->next_in_chain != index) { + assert(e->isEndOfChain() == false); + e = &entry(e->next_in_chain); + } + + if (e->isTombstone() && pos->isEndOfChain()) { + // Tombstone has nothing else to point + // to, so mark it empty. + e->next_in_chain = -2; + } else { + e->next_in_chain = pos->next_in_chain; + } + + pos->clear(); + } + else if (pos->isEndOfChain() == false) { + // We're the head of our chain, and there are + // additional elements. + // + // We need to put a tombstone here. + // + // We can't clear the element, because the + // rest of the elements in the chain must be + // linked to this position. + // + // We can't move any of the succeeding + // elements in the chain (i.e. to fill this + // entry), because we don't want to invalidate + // any other existing iterators. + pos->makeTombstone(); + } else { + // We're the head of the chain, but we're the + // only member of the chain. + pos->clear(); + } + + entry_count--; + + return true; + } + + + /// Remove all entries from the hash table. + void clear() + { + if (table != NULL) + { + // Delete the entries. + for (int i = 0, n = size_mask; i <= n; i++) + { + Entry * e = &entry(i); + if (e->isEmpty() == false && e->isTombstone() == false) + { + e->clear(); + } + } + mem::free(table); + table = NULL; + entry_count = 0; + size_mask = -1; + } + } + + + /// Returns true if the hash is empty. + bool isEmpty() const + { + return table == NULL || entry_count == 0; + } + + + /** Retrieve the value under the given key. + * + * If there's no value under the key, then return false and leave + * *value alone. + * + * If there is a value, return true, and set *value to the entry's + * value. + * + * If value == NULL, return true or false according to the + * presence of the key, but don't touch *value. + */ + bool get(const T& key, U* value = NULL) const + { + int index = findIndex(key); + if (index >= 0) + { + if (value) { + *value = entry(index).value; // take care with side-effects! + } + return true; + } + return false; + } + + /// Determine if the given key is contained in the hash. + bool contains(const T & key) const + { + return get(key); + } + + /// Number of entries in the hash. + int size() const + { + return entry_count; + } + + /// Number of entries in the hash. + int count() const + { + return size(); + } + + + /** + * Resize the hash table to fit one more entry. Often this + * doesn't involve any action. + */ + void checkExpand() + { + if (table == NULL) { + // Initial creation of table. Make a minimum-sized table. + setRawCapacity(16); + } + else if (entry_count * 3 > (size_mask + 1) * 2) { + // Table is more than 2/3rds full. Expand. + setRawCapacity(entry_count * 2); + } + } + + + /// Hint the bucket count to >= n. + void resize(int n) + { + // Not really sure what this means in relation to + // STLport's hash_map... they say they "increase the + // bucket count to at least n" -- but does that mean + // their real capacity after resize(n) is more like + // n*2 (since they do linked-list chaining within + // buckets?). + setCapacity(n); + } + + /** + * Size the hash so that it can comfortably contain the given + * number of elements. If the hash already contains more + * elements than new_size, then this may be a no-op. + */ + void setCapacity(int new_size) + { + int new_raw_size = (new_size * 3) / 2; + if (new_raw_size < size()) { return; } + + setRawCapacity(new_raw_size); + } + + /// Behaves much like std::pair. + struct Entry + { + int next_in_chain; // internal chaining for collisions + uint hash_value; // avoids recomputing. Worthwhile? + T key; + U value; + + Entry() : next_in_chain(-2) {} + Entry(const Entry& e) + : next_in_chain(e.next_in_chain), hash_value(e.hash_value), key(e.key), value(e.value) + { + } + Entry(const T& k, const U& v, int next, int hash) + : next_in_chain(next), hash_value(hash), key(k), value(v) + { + } + bool isEmpty() const { return next_in_chain == -2; } + bool isEndOfChain() const { return next_in_chain == -1; } + bool isTombstone() const { return hash_value == TOMBSTONE_HASH; } + + void clear() + { + key.~T(); // placement delete + value.~U(); // placement delete + next_in_chain = -2; + hash_value = ~TOMBSTONE_HASH; + } + + void makeTombstone() + { + key.~T(); + value.~U(); + hash_value = TOMBSTONE_HASH; + } + }; + + + // HashMap enumerator. + typedef int PseudoIndex; + PseudoIndex start() const { PseudoIndex i = 0; findNext(i); return i; } + bool isDone(const PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); return i == size_mask+1; }; + void advance(PseudoIndex & i) const { nvDebugCheck(i <= size_mask+1); i++; findNext(i); } + +#if NV_CC_GNUC + Entry & operator[]( const PseudoIndex & i ) { + Entry & e = entry(i); + nvDebugCheck(e.isTombstone() == false); + return e; + } + const Entry & operator[]( const PseudoIndex & i ) const { + const Entry & e = entry(i); + nvDebugCheck(e.isTombstone() == false); + return e; + } +#elif NV_CC_MSVC + Entry & operator[]( const PseudoIndexWrapper & i ) { + Entry & e = entry(i(this)); + nvDebugCheck(e.isTombstone() == false); + return e; + } + const Entry & operator[]( const PseudoIndexWrapper & i ) const { + const Entry & e = entry(i(this)); + nvDebugCheck(e.isTombstone() == false); + return e; + } +#endif + + + + private: + static const uint TOMBSTONE_HASH = (uint) -1; + + uint compute_hash(const T& key) const + { + H hash; + uint hash_value = hash(key); + if (hash_value == TOMBSTONE_HASH) { + hash_value ^= 0x8000; + } + return hash_value; + } + + // Find the index of the matching entry. If no match, then return -1. + int findIndex(const T& key) const + { + if (table == NULL) return -1; + + E equal; + + uint hash_value = compute_hash(key); + int index = hash_value & size_mask; + + const Entry * e = &entry(index); + if (e->isEmpty()) return -1; + if (e->isTombstone() == false && int(e->hash_value & size_mask) != index) { + // occupied by a collider + return -1; + } + + for (;;) + { + nvCheck(e->isTombstone() || (e->hash_value & size_mask) == (hash_value & size_mask)); + + if (e->hash_value == hash_value && equal(e->key, key)) + { + // Found it. + return index; + } + nvDebugCheck(e->isTombstone() || !equal(e->key, key)); // keys are equal, but hash differs! + + // Keep looking through the chain. + index = e->next_in_chain; + if (index == -1) break; // end of chain + + nvCheck(index >= 0 && index <= size_mask); + e = &entry(index); + + nvCheck(e->isEmpty() == false || e->isTombstone()); + } + return -1; + } + + // Return the index of the newly cleared element. + int removeTombstone(int index) { + Entry* e = &entry(index); + nvCheck(e->isTombstone()); + nvCheck(!e->isEndOfChain()); + + // Move the next element of the chain into the + // tombstone slot, and return the vacated element. + int new_blank_index = e->next_in_chain; + Entry* new_blank = &entry(new_blank_index); + new (e) Entry(*new_blank); + new_blank->clear(); + return new_blank_index; + } + + // Helpers. + Entry & entry(int index) + { + nvDebugCheck(table != NULL); + nvDebugCheck(index >= 0 && index <= size_mask); + return table[index]; + } + const Entry & entry(int index) const + { + nvDebugCheck(table != NULL); + nvDebugCheck(index >= 0 && index <= size_mask); + return table[index]; + } + + + /** + * Resize the hash table to the given size (Rehash the + * contents of the current table). The arg is the number of + * hash table entries, not the number of elements we should + * actually contain (which will be less than this). + */ + void setRawCapacity(int new_size) + { + if (new_size <= 0) { + // Special case. + clear(); + return; + } + + // Force new_size to be a power of two. + new_size = nextPowerOfTwo(new_size); + + HashMap new_hash; + new_hash.table = (Entry *) mem::malloc(sizeof(Entry) * new_size); + nvDebugCheck(new_hash.table != NULL); + + new_hash.entry_count = 0; + new_hash.size_mask = new_size - 1; + for (int i = 0; i < new_size; i++) + { + new_hash.entry(i).next_in_chain = -2; // mark empty + } + + // Copy stuff to new_hash + if (table != NULL) + { + for (int i = 0, n = size_mask; i <= n; i++) + { + Entry * e = &entry(i); + if (e->isEmpty() == false && e->isTombstone() == false) + { + // Insert old entry into new hash. + new_hash.add(e->key, e->value); + e->clear(); // placement delete of old element + } + } + + // Delete our old data buffer. + mem::free(table); + } + + // Steal new_hash's data. + entry_count = new_hash.entry_count; + size_mask = new_hash.size_mask; + table = new_hash.table; + new_hash.entry_count = 0; + new_hash.size_mask = -1; + new_hash.table = NULL; + } + + // Move the enumerator to the next valid element. + void findNext(PseudoIndex & i) const { + while (i <= size_mask) { + const Entry & e = entry(i); + if (e.isEmpty() == false && e.isTombstone() == false) { + break; + } + i++; + } + } + + + int entry_count; + int size_mask; + Entry * table; + + }; + +} // nv namespace + +#endif // NV_CORE_HASHMAP_H diff --git a/src/nvcore/Library.h b/src/nvcore/Library.h index 00879f0..d7bd589 100644 --- a/src/nvcore/Library.h +++ b/src/nvcore/Library.h @@ -1,5 +1,6 @@ // This code is in the public domain -- castano@gmail.com +#pragma once #ifndef NV_CORE_LIBRARY_H #define NV_CORE_LIBRARY_H diff --git a/src/nvcore/Memory.cpp b/src/nvcore/Memory.cpp index 7ece018..417fc9d 100644 --- a/src/nvcore/Memory.cpp +++ b/src/nvcore/Memory.cpp @@ -1,3 +1,4 @@ +// This code is in the public domain -- Ignacio Castaņo #include "Memory.h" #include "Debug.h" @@ -13,24 +14,24 @@ using namespace nv; void * nv::mem::malloc(size_t size) { - return ::malloc(size); + return ::malloc(size); } void * nv::mem::malloc(size_t size, const char * file, int line) { - NV_UNUSED(file); - NV_UNUSED(line); - return ::malloc(size); + NV_UNUSED(file); + NV_UNUSED(line); + return ::malloc(size); } void nv::mem::free(const void * ptr) { - ::free(const_cast(ptr)); + ::free(const_cast(ptr)); } void * nv::mem::realloc(void * ptr, size_t size) { - nvDebugCheck(ptr != NULL || size != 0); // undefined realloc behavior. - return ::realloc(ptr, size); + nvDebugCheck(ptr != NULL || size != 0); // undefined realloc behavior. + return ::realloc(ptr, size); } diff --git a/src/nvcore/Memory.h b/src/nvcore/Memory.h index 43fbe50..4f7e926 100644 --- a/src/nvcore/Memory.h +++ b/src/nvcore/Memory.h @@ -1,5 +1,6 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio CastaÃąo +#pragma once #ifndef NV_CORE_MEMORY_H #define NV_CORE_MEMORY_H diff --git a/src/nvcore/Ptr.h b/src/nvcore/Ptr.h index 27e9965..70f6174 100644 --- a/src/nvcore/Ptr.h +++ b/src/nvcore/Ptr.h @@ -1,4 +1,4 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio Castaņo #ifndef NV_CORE_PTR_H #define NV_CORE_PTR_H @@ -6,266 +6,316 @@ #include "nvcore.h" #include "Debug.h" -#include // NULL namespace nv { - -/** Simple auto pointer template class. - * - * This is very similar to the standard auto_ptr class, but with some - * additional limitations to make its use less error prone: - * - Copy constructor and assignment operator are disabled. - * - reset method is removed. - * - * The semantics of the standard auto_ptr are not clear and change depending - * on the std implementation. For a discussion of the problems of auto_ptr read: - * http://www.awprofessional.com/content/images/020163371X/autoptrupdate\auto_ptr_update.html - */ -template -class AutoPtr -{ - NV_FORBID_COPY(AutoPtr); - NV_FORBID_HEAPALLOC(); -public: - - /// Ctor. - AutoPtr(T * p = NULL) : m_ptr(p) { } + class WeakProxy; - template - AutoPtr(Q * p) : m_ptr(static_cast(p)) { } - - /** Dtor. Deletes owned pointer. */ - ~AutoPtr() { - delete m_ptr; - m_ptr = NULL; - } + /** Simple auto pointer template class. + * + * This is very similar to the standard auto_ptr class, but with some + * additional limitations to make its use less error prone: + * - Copy constructor and assignment operator are disabled. + * - reset method is removed. + * + * The semantics of the standard auto_ptr are not clear and change depending + * on the std implementation. For a discussion of the problems of auto_ptr read: + * http://www.awprofessional.com/content/images/020163371X/autoptrupdate\auto_ptr_update.html + */ + template + class AutoPtr + { + NV_FORBID_COPY(AutoPtr); + NV_FORBID_HEAPALLOC(); + public: - /** Delete owned pointer and assign new one. */ - void operator=( T * p ) { - if (p != m_ptr) - { - delete m_ptr; - m_ptr = p; - } - } + /// Ctor. + AutoPtr(T * p = NULL) : m_ptr(p) { } - template - void operator=( Q * p ) { - if (p != m_ptr) - { - delete m_ptr; - m_ptr = static_cast(p); - } - } + template + AutoPtr(Q * p) : m_ptr(static_cast(p)) { } - /** Member access. */ - T * operator -> () const { - nvDebugCheck(m_ptr != NULL); - return m_ptr; - } + /// Dtor. Deletes owned pointer. + ~AutoPtr() { + delete m_ptr; + m_ptr = NULL; + } - /** Get reference. */ - T & operator*() const { - nvDebugCheck(m_ptr != NULL); - return *m_ptr; - } + /// Delete owned pointer and assign new one. + void operator=( T * p ) { + if (p != m_ptr) + { + delete m_ptr; + m_ptr = p; + } + } - /** Get pointer. */ - T * ptr() const { return m_ptr; } - - /** Relinquish ownership of the underlying pointer and returns that pointer. */ - T * release() { - T * tmp = m_ptr; - m_ptr = NULL; - return tmp; - } - - /** Const pointer equal comparation. */ - friend bool operator == (const AutoPtr & ap, const T * const p) { - return (ap.ptr() == p); - } + template + void operator=( Q * p ) { + if (p != m_ptr) + { + delete m_ptr; + m_ptr = static_cast(p); + } + } - /** Const pointer nequal comparation. */ - friend bool operator != (const AutoPtr & ap, const T * const p) { - return (ap.ptr() != p); - } + /// Member access. + T * operator -> () const { + nvDebugCheck(m_ptr != NULL); + return m_ptr; + } - /** Const pointer equal comparation. */ - friend bool operator == (const T * const p, const AutoPtr & ap) { - return (ap.ptr() == p); - } + /// Get reference. + T & operator*() const { + nvDebugCheck(m_ptr != NULL); + return *m_ptr; + } - /** Const pointer nequal comparation. */ - friend bool operator != (const T * const p, const AutoPtr & ap) { - return (ap.ptr() != p); - } + /// Get pointer. + T * ptr() const { return m_ptr; } -private: - T * m_ptr; -}; + /// Relinquish ownership of the underlying pointer and returns that pointer. + T * release() { + T * tmp = m_ptr; + m_ptr = NULL; + return tmp; + } + + /// Const pointer equal comparation. + friend bool operator == (const AutoPtr & ap, const T * const p) { + return (ap.ptr() == p); + } + + /// Const pointer nequal comparation. + friend bool operator != (const AutoPtr & ap, const T * const p) { + return (ap.ptr() != p); + } + + /// Const pointer equal comparation. + friend bool operator == (const T * const p, const AutoPtr & ap) { + return (ap.ptr() == p); + } + + /// Const pointer nequal comparation. + friend bool operator != (const T * const p, const AutoPtr & ap) { + return (ap.ptr() != p); + } + + private: + T * m_ptr; + }; -/// Smart pointer template class. -template -class SmartPtr { -public: + /// Smart pointer template class. + template + class SmartPtr { + public: - // BaseClass must implement addRef() and release(). - typedef SmartPtr ThisType; + // BaseClass must implement addRef() and release(). + typedef SmartPtr ThisType; - /// Default ctor. - SmartPtr() : m_ptr(NULL) - { - } + /// Default ctor. + SmartPtr() : m_ptr(NULL) + { + } - /** Other type assignment. */ - template - SmartPtr( const SmartPtr & tc ) - { - m_ptr = static_cast( tc.ptr() ); - if( m_ptr ) { - m_ptr->addRef(); - } - } + /// Other type assignment. + template + SmartPtr( const SmartPtr & tc ) + { + m_ptr = static_cast( tc.ptr() ); + if (m_ptr) { + m_ptr->addRef(); + } + } - /** Copy ctor. */ - SmartPtr( const ThisType & bc ) - { - m_ptr = bc.ptr(); - if( m_ptr ) { - m_ptr->addRef(); - } - } + /// Copy ctor. + SmartPtr( const ThisType & bc ) + { + m_ptr = bc.ptr(); + if (m_ptr) { + m_ptr->addRef(); + } + } - /** Copy cast ctor. SmartPtr(NULL) is valid. */ - explicit SmartPtr( BaseClass * bc ) - { - m_ptr = bc; - if( m_ptr ) { - m_ptr->addRef(); - } - } + /// Copy cast ctor. SmartPtr(NULL) is valid. + explicit SmartPtr( BaseClass * bc ) + { + m_ptr = bc; + if (m_ptr) { + m_ptr->addRef(); + } + } - /** Dtor. */ - ~SmartPtr() - { - set(NULL); - } + /// Dtor. + ~SmartPtr() + { + set(NULL); + } - /** @name Accessors: */ - //@{ - /** -> operator. */ - BaseClass * operator -> () const - { - nvCheck( m_ptr != NULL ); - return m_ptr; - } + /// -> operator. + BaseClass * operator -> () const + { + nvCheck( m_ptr != NULL ); + return m_ptr; + } - /** * operator. */ - BaseClass & operator*() const - { - nvCheck( m_ptr != NULL ); - return *m_ptr; - } + /// * operator. + BaseClass & operator*() const + { + nvCheck( m_ptr != NULL ); + return *m_ptr; + } - /** Get pointer. */ - BaseClass * ptr() const - { - return m_ptr; - } - //@} + /// Get pointer. + BaseClass * ptr() const + { + return m_ptr; + } + + /// Other type assignment. + template + void operator = ( const SmartPtr & tc ) + { + set( static_cast(tc.ptr()) ); + } + + /// This type assignment. + void operator = ( const ThisType & bc ) + { + set( bc.ptr() ); + } + + /// Pointer assignment. + void operator = ( BaseClass * bc ) + { + set( bc ); + } - /** @name Mutators: */ - //@{ - /** Other type assignment. */ - template - void operator = ( const SmartPtr & tc ) - { - set( static_cast(tc.ptr()) ); - } + /// Other type equal comparation. + template + bool operator == ( const SmartPtr & other ) const + { + return m_ptr == other.ptr(); + } - /** This type assignment. */ - void operator = ( const ThisType & bc ) - { - set( bc.ptr() ); - } + /// This type equal comparation. + bool operator == ( const ThisType & bc ) const + { + return m_ptr == bc.ptr(); + } - /** Pointer assignment. */ - void operator = ( BaseClass * bc ) - { - set( bc ); - } - //@} + /// Const pointer equal comparation. + bool operator == ( const BaseClass * const bc ) const + { + return m_ptr == bc; + } + + /// Other type not equal comparation. + template + bool operator != ( const SmartPtr & other ) const + { + return m_ptr != other.ptr(); + } + + /// Other type not equal comparation. + bool operator != ( const ThisType & bc ) const + { + return m_ptr != bc.ptr(); + } + + /// Const pointer not equal comparation. + bool operator != (const BaseClass * const bc) const + { + return m_ptr != bc; + } + + /// This type lower than comparation. + bool operator < (const ThisType & p) const + { + return m_ptr < p.ptr(); + } + + bool isValid() const { + return isValidPtr(m_ptr); + } + + private: + + // Set this pointer. + void set( BaseClass * p ) + { + if (p) p->addRef(); + if (m_ptr) m_ptr->release(); + m_ptr = p; + } + + private: + + BaseClass * m_ptr; + + }; - /** @name Comparators: */ - //@{ - /** Other type equal comparation. */ - template - bool operator == ( const SmartPtr & other ) const - { - return m_ptr == other.ptr(); - } + /// Smart pointer template class. + template + class WeakPtr { + public: - /** This type equal comparation. */ - bool operator == ( const ThisType & bc ) const - { - return m_ptr == bc.ptr(); - } + WeakPtr() {} - /** Const pointer equal comparation. */ - bool operator == ( const BaseClass * const bc ) const - { - return m_ptr == bc; - } + WeakPtr(T * p) { operator=(p); } + WeakPtr(const SmartPtr & p) { operator=(p.ptr()); } - /** Other type not equal comparation. */ - template - bool operator != ( const SmartPtr & other ) const - { - return m_ptr != other.ptr(); - } - - /** Other type not equal comparation. */ - bool operator != ( const ThisType & bc ) const - { - return m_ptr != bc.ptr(); - } + // Default constructor and assignment from weak_ptr are OK. - /** Const pointer not equal comparation. */ - bool operator != (const BaseClass * const bc) const - { - return m_ptr != bc; - } + void operator=(T * p) + { + if (p) { + m_proxy = p->getWeakProxy(); + assert(m_proxy != NULL); + assert(m_proxy->ptr() == p); + } + else { + m_proxy = NULL; + } + } - /** This type lower than comparation. */ - bool operator < (const ThisType & p) const - { - return m_ptr < p.ptr(); - } - //@} + void operator=(const SmartPtr & ptr) { operator=(ptr.ptr()); } -private: + bool operator==(const SmartPtr & p) const { return ptr() == p.ptr(); } + bool operator!=(const SmartPtr & p) const { return ptr() != p.ptr(); } - /** Set this pointer. */ - void set( BaseClass * p ) - { - if( m_ptr != p ) { - if( m_ptr ) m_ptr->release(); - if( p ) p->addRef(); - m_ptr = p; - } - } + bool operator==(const WeakPtr & p) const { return ptr() == p.ptr(); } + bool operator!=(const WeakPtr & p) const { return ptr() != p.ptr(); } -private: + bool operator==(T * p) const { return ptr() == p; } + bool operator!=(T * p) const { return ptr() != p; } - BaseClass * m_ptr; + T * operator->() const + { + T * p = ptr(); + assert(p != NULL); + return p; + } + + T * ptr() const + { + if (m_proxy != NULL) { + return static_cast(m_proxy->ptr()); + } + return NULL; + } + + private: + + mutable SmartPtr m_proxy; + + }; -}; } // nv namespace diff --git a/src/nvcore/RefCounted.cpp b/src/nvcore/RefCounted.cpp deleted file mode 100644 index 595c74c..0000000 --- a/src/nvcore/RefCounted.cpp +++ /dev/null @@ -1,9 +0,0 @@ -// This code is in the public domain -- castanyo@yahoo.es - -#include "RefCounted.h" - -using namespace nv; - -int nv::RefCounted::s_total_ref_count = 0; -int nv::RefCounted::s_total_obj_count = 0; - diff --git a/src/nvcore/RefCounted.h b/src/nvcore/RefCounted.h index 9ff3bff..b8d68ed 100644 --- a/src/nvcore/RefCounted.h +++ b/src/nvcore/RefCounted.h @@ -1,4 +1,4 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio Castaņo #ifndef NV_CORE_REFCOUNTED_H #define NV_CORE_REFCOUNTED_H @@ -6,107 +6,142 @@ #include "nvcore.h" #include "Debug.h" +#define NV_DECLARE_PTR(Class) \ + template class SmartPtr; \ + typedef SmartPtr Class ## Ptr; \ + typedef SmartPtr Class ## ConstPtr + namespace nv { + /// Weak proxy. + class WeakProxy + { + NV_FORBID_COPY(WeakProxy); + public: + /// Ctor. + WeakProxy(void * ptr) : m_count(0), m_ptr(ptr) { } - /// Reference counted base class to be used with SmartPtr and WeakPtr. - class RefCounted - { - NV_FORBID_COPY(RefCounted); - public: + /// Dtor. + ~WeakProxy() + { + nvCheck( m_count == 0 ); + } - /// Ctor. - RefCounted() : m_count(0)/*, m_weak_proxy(NULL)*/ - { - s_total_obj_count++; - } + /// Increase reference count. + uint addRef() const + { + m_count++; + return m_count; + } - /// Virtual dtor. - virtual ~RefCounted() - { - nvCheck( m_count == 0 ); - nvCheck( s_total_obj_count > 0 ); - s_total_obj_count--; - } + /// Decrease reference count and remove when 0. + uint release() const + { + nvCheck( m_count > 0 ); + + m_count--; + if( m_count == 0 ) { + delete this; + return 0; + } + return m_count; + } + + /// WeakPtr's call this to determine if their pointer is valid or not. + bool isAlive() const { + return m_ptr != NULL; + } + + /// Only the actual object should call this. + void notifyObjectDied() { + m_ptr = NULL; + } + + /// Return proxy pointer. + void * ptr() const { + return m_ptr; + } + + private: + mutable int m_count; + void * m_ptr; + }; - /// Increase reference count. - uint addRef() const - { - s_total_ref_count++; - m_count++; - return m_count; - } + /// Reference counted base class to be used with SmartPtr and WeakPtr. + class RefCounted + { + NV_FORBID_COPY(RefCounted); + public: + + /// Ctor. + RefCounted() : m_count(0), m_weak_proxy(NULL) + { + } + + /// Virtual dtor. + virtual ~RefCounted() + { + nvCheck( m_count == 0 ); + releaseWeakProxy(); + } - /// Decrease reference count and remove when 0. - uint release() const - { - nvCheck( m_count > 0 ); - - s_total_ref_count--; - m_count--; - if( m_count == 0 ) { - // releaseWeakProxy(); - delete this; - return 0; - } - return m_count; - } - /* - /// Get weak proxy. - WeakProxy * getWeakProxy() const - { - if (m_weak_proxy == NULL) { - m_weak_proxy = new WeakProxy; - m_weak_proxy->AddRef(); - } - return m_weak_proxy; - } - - /// Release the weak proxy. - void releaseWeakProxy() const - { - if (m_weak_proxy != NULL) { - m_weak_proxy->NotifyObjectDied(); - m_weak_proxy->Release(); - m_weak_proxy = NULL; - } - } - */ - /** @name Debug methods: */ - //@{ - /// Get reference count. - int refCount() const - { - return m_count; - } - - /// Get total number of objects. - static int totalObjectCount() - { - return s_total_obj_count; - } - - /// Get total number of references. - static int totalReferenceCount() - { - return s_total_ref_count; - } - //@} + /// Increase reference count. + uint addRef() const + { + m_count++; + return m_count; + } - private: + /// Decrease reference count and remove when 0. + uint release() const + { + nvCheck( m_count > 0 ); - NVCORE_API static int s_total_ref_count; - NVCORE_API static int s_total_obj_count; + m_count--; + if( m_count == 0 ) { + delete this; + return 0; + } + return m_count; + } - mutable int m_count; - // mutable WeakProxy * weak_proxy; + /// Get weak proxy. + WeakProxy * getWeakProxy() const + { + if (m_weak_proxy == NULL) { + m_weak_proxy = new WeakProxy((void *)this); + m_weak_proxy->addRef(); + } + return m_weak_proxy; + } - }; + /// Release the weak proxy. + void releaseWeakProxy() const + { + if (m_weak_proxy != NULL) { + m_weak_proxy->notifyObjectDied(); + m_weak_proxy->release(); + m_weak_proxy = NULL; + } + } + /// Get reference count. + int refCount() const + { + return m_count; + } + + + private: + + mutable int m_count; + mutable WeakProxy * m_weak_proxy; + + }; } // nv namespace diff --git a/src/nvcore/StdStream.h b/src/nvcore/StdStream.h index 31a64f4..d24d6ac 100644 --- a/src/nvcore/StdStream.h +++ b/src/nvcore/StdStream.h @@ -1,9 +1,11 @@ -// This code is in the public domain -- castano@gmail.com +// This code is in the public domain -- Ignacio Castaņo +#pragma once #ifndef NV_CORE_STDSTREAM_H #define NV_CORE_STDSTREAM_H -#include +#include "nvcore.h" +#include "Stream.h" #include // fopen #include // memcpy @@ -12,358 +14,358 @@ namespace nv { -// Portable version of fopen. -inline FILE * fileOpen(const char * fileName, const char * mode) -{ - nvCheck(fileName != NULL); + // Portable version of fopen. + inline FILE * fileOpen(const char * fileName, const char * mode) + { + nvCheck(fileName != NULL); #if NV_CC_MSVC && _MSC_VER >= 1400 - FILE * fp; - if (fopen_s(&fp, fileName, mode) == 0) { - return fp; - } - return NULL; + FILE * fp; + if (fopen_s(&fp, fileName, mode) == 0) { + return fp; + } + return NULL; #else - return fopen(fileName, mode); + return fopen(fileName, mode); #endif -} + } -/// Base stdio stream. -class NVCORE_CLASS StdStream : public Stream -{ - NV_FORBID_COPY(StdStream); -public: + /// Base stdio stream. + class NVCORE_CLASS StdStream : public Stream + { + NV_FORBID_COPY(StdStream); + public: - /// Ctor. - StdStream( FILE * fp, bool autoclose=true ) : - m_fp(fp), m_autoclose(autoclose) { } - - /// Dtor. - virtual ~StdStream() - { - if( m_fp != NULL && m_autoclose ) { - fclose( m_fp ); - } - } + /// Ctor. + StdStream( FILE * fp, bool autoclose=true ) : + m_fp(fp), m_autoclose(autoclose) { } + + /// Dtor. + virtual ~StdStream() + { + if( m_fp != NULL && m_autoclose ) { + fclose( m_fp ); + } + } - /** @name Stream implementation. */ - //@{ - virtual void seek( uint pos ) - { - nvDebugCheck(m_fp != NULL); - nvDebugCheck(pos < size()); - fseek(m_fp, pos, SEEK_SET); - } - - virtual uint tell() const - { - nvDebugCheck(m_fp != NULL); - return ftell(m_fp); - } - - virtual uint size() const - { - nvDebugCheck(m_fp != NULL); - uint pos = ftell(m_fp); - fseek(m_fp, 0, SEEK_END); - uint end = ftell(m_fp); - fseek(m_fp, pos, SEEK_SET); - return end; - } - - virtual bool isError() const - { - return m_fp == NULL || ferror( m_fp ) != 0; - } + /** @name Stream implementation. */ + //@{ + virtual void seek( uint pos ) + { + nvDebugCheck(m_fp != NULL); + nvDebugCheck(pos < size()); + fseek(m_fp, pos, SEEK_SET); + } - virtual void clearError() - { - nvDebugCheck(m_fp != NULL); - clearerr(m_fp); - } - - virtual bool isAtEnd() const - { - nvDebugCheck(m_fp != NULL); - return feof( m_fp ) != 0; - } - - /// Always true. - virtual bool isSeekable() const { return true; } - //@} + virtual uint tell() const + { + nvDebugCheck(m_fp != NULL); + return ftell(m_fp); + } -protected: + virtual uint size() const + { + nvDebugCheck(m_fp != NULL); + uint pos = ftell(m_fp); + fseek(m_fp, 0, SEEK_END); + uint end = ftell(m_fp); + fseek(m_fp, pos, SEEK_SET); + return end; + } - FILE * m_fp; - bool m_autoclose; + virtual bool isError() const + { + return m_fp == NULL || ferror( m_fp ) != 0; + } -}; + virtual void clearError() + { + nvDebugCheck(m_fp != NULL); + clearerr(m_fp); + } + + virtual bool isAtEnd() const + { + nvDebugCheck(m_fp != NULL); + return feof( m_fp ) != 0; + } + + /// Always true. + virtual bool isSeekable() const { return true; } + //@} + + protected: + + FILE * m_fp; + bool m_autoclose; + + }; -/// Standard output stream. -class NVCORE_CLASS StdOutputStream : public StdStream -{ - NV_FORBID_COPY(StdOutputStream); -public: + /// Standard output stream. + class NVCORE_CLASS StdOutputStream : public StdStream + { + NV_FORBID_COPY(StdOutputStream); + public: - /// Construct stream by file name. - StdOutputStream( const char * name ) : - StdStream(fileOpen(name, "wb")) { } + /// Construct stream by file name. + StdOutputStream( const char * name ) : + StdStream(fileOpen(name, "wb")) { } - /// Construct stream by file handle. - StdOutputStream( FILE * fp, bool autoclose=true ) : StdStream(fp, autoclose) - { - } + /// Construct stream by file handle. + StdOutputStream( FILE * fp, bool autoclose=true ) : StdStream(fp, autoclose) + { + } - /** @name Stream implementation. */ - //@{ - /// Write data. - virtual uint serialize( void * data, uint len ) - { - nvDebugCheck(data != NULL); - nvDebugCheck(m_fp != NULL); - return (uint)fwrite(data, 1, len, m_fp); - } - - virtual bool isLoading() const - { - return false; - } - - virtual bool isSaving() const - { - return true; - } - //@} + /** @name Stream implementation. */ + //@{ + /// Write data. + virtual uint serialize( void * data, uint len ) + { + nvDebugCheck(data != NULL); + nvDebugCheck(m_fp != NULL); + return (uint)fwrite(data, 1, len, m_fp); + } -}; + virtual bool isLoading() const + { + return false; + } + + virtual bool isSaving() const + { + return true; + } + //@} + + }; -/// Standard input stream. -class NVCORE_CLASS StdInputStream : public StdStream -{ - NV_FORBID_COPY(StdInputStream); -public: + /// Standard input stream. + class NVCORE_CLASS StdInputStream : public StdStream + { + NV_FORBID_COPY(StdInputStream); + public: - /// Construct stream by file name. - StdInputStream( const char * name ) : - StdStream(fileOpen(name, "rb")) { } + /// Construct stream by file name. + StdInputStream( const char * name ) : + StdStream(fileOpen(name, "rb")) { } - /// Construct stream by file handle. - StdInputStream( FILE * fp, bool autoclose=true ) : StdStream(fp, autoclose) - { - } + /// Construct stream by file handle. + StdInputStream( FILE * fp, bool autoclose=true ) : StdStream(fp, autoclose) + { + } - /** @name Stream implementation. */ - //@{ - /// Read data. - virtual uint serialize( void * data, uint len ) - { - nvDebugCheck(data != NULL); - nvDebugCheck(m_fp != NULL); - return (uint)fread(data, 1, len, m_fp); - } - - virtual bool isLoading() const - { - return true; - } - - virtual bool isSaving() const - { - return false; - } - //@} -}; + /** @name Stream implementation. */ + //@{ + /// Read data. + virtual uint serialize( void * data, uint len ) + { + nvDebugCheck(data != NULL); + nvDebugCheck(m_fp != NULL); + return (uint)fread(data, 1, len, m_fp); + } + + virtual bool isLoading() const + { + return true; + } + + virtual bool isSaving() const + { + return false; + } + //@} + }; -/// Memory input stream. -class NVCORE_CLASS MemoryInputStream : public Stream -{ - NV_FORBID_COPY(MemoryInputStream); -public: + /// Memory input stream. + class NVCORE_CLASS MemoryInputStream : public Stream + { + NV_FORBID_COPY(MemoryInputStream); + public: - /// Ctor. - MemoryInputStream( const uint8 * mem, uint size ) : - m_mem(mem), m_ptr(mem), m_size(size) { } + /// Ctor. + MemoryInputStream( const uint8 * mem, uint size ) : + m_mem(mem), m_ptr(mem), m_size(size) { } - /** @name Stream implementation. */ - //@{ - /// Read data. - virtual uint serialize( void * data, uint len ) - { - nvDebugCheck(data != NULL); - nvDebugCheck(!isError()); + /** @name Stream implementation. */ + //@{ + /// Read data. + virtual uint serialize( void * data, uint len ) + { + nvDebugCheck(data != NULL); + nvDebugCheck(!isError()); - uint left = m_size - tell(); - if (len > left) len = left; - - memcpy( data, m_ptr, len ); - m_ptr += len; - - return len; - } - - virtual void seek( uint pos ) - { - nvDebugCheck(!isError()); - m_ptr = m_mem + pos; - nvDebugCheck(!isError()); - } - - virtual uint tell() const - { - nvDebugCheck(m_ptr >= m_mem); - return uint(m_ptr - m_mem); - } - - virtual uint size() const - { - return m_size; - } - - virtual bool isError() const - { - return m_mem == NULL || m_ptr > m_mem + m_size || m_ptr < m_mem; - } - - virtual void clearError() - { - // Nothing to do. - } + uint left = m_size - tell(); + if (len > left) len = left; - virtual bool isAtEnd() const - { - return m_ptr == m_mem + m_size; - } - - /// Always true. - virtual bool isSeekable() const - { - return true; - } - - virtual bool isLoading() const - { - return true; - } - - virtual bool isSaving() const - { - return false; - } - //@} + memcpy( data, m_ptr, len ); + m_ptr += len; - -private: + return len; + } - const uint8 * m_mem; - const uint8 * m_ptr; - uint m_size; + virtual void seek( uint pos ) + { + nvDebugCheck(!isError()); + m_ptr = m_mem + pos; + nvDebugCheck(!isError()); + } -}; + virtual uint tell() const + { + nvDebugCheck(m_ptr >= m_mem); + return uint(m_ptr - m_mem); + } + + virtual uint size() const + { + return m_size; + } + + virtual bool isError() const + { + return m_mem == NULL || m_ptr > m_mem + m_size || m_ptr < m_mem; + } + + virtual void clearError() + { + // Nothing to do. + } + + virtual bool isAtEnd() const + { + return m_ptr == m_mem + m_size; + } + + /// Always true. + virtual bool isSeekable() const + { + return true; + } + + virtual bool isLoading() const + { + return true; + } + + virtual bool isSaving() const + { + return false; + } + //@} -/// Protected input stream. -class NVCORE_CLASS ProtectedStream : public Stream -{ - NV_FORBID_COPY(ProtectedStream); -public: + private: - /// Ctor. - ProtectedStream( Stream & s ) : m_s(&s), m_autodelete(false) - { - } + const uint8 * m_mem; + const uint8 * m_ptr; + uint m_size; - /// Ctor. - ProtectedStream( Stream * s, bool autodelete = true ) : - m_s(s), m_autodelete(autodelete) - { - nvDebugCheck(m_s != NULL); - } + }; - /// Dtor. - virtual ~ProtectedStream() - { - if( m_autodelete ) { - delete m_s; - } - } - /** @name Stream implementation. */ - //@{ - /// Read data. - virtual uint serialize( void * data, uint len ) - { - nvDebugCheck(data != NULL); - len = m_s->serialize( data, len ); - - if( m_s->isError() ) { - throw std::exception(); - } + /// Protected input stream. + class NVCORE_CLASS ProtectedStream : public Stream + { + NV_FORBID_COPY(ProtectedStream); + public: - return len; - } - - virtual void seek( uint pos ) - { - m_s->seek( pos ); - - if( m_s->isError() ) { - throw std::exception(); - } - } - - virtual uint tell() const - { - return m_s->tell(); - } - - virtual uint size() const - { - return m_s->size(); - } - - virtual bool isError() const - { - return m_s->isError(); - } + /// Ctor. + ProtectedStream( Stream & s ) : m_s(&s), m_autodelete(false) + { + } - virtual void clearError() - { - m_s->clearError(); - } + /// Ctor. + ProtectedStream( Stream * s, bool autodelete = true ) : + m_s(s), m_autodelete(autodelete) + { + nvDebugCheck(m_s != NULL); + } - virtual bool isAtEnd() const - { - return m_s->isAtEnd(); - } - - virtual bool isSeekable() const - { - return m_s->isSeekable(); - } - - virtual bool isLoading() const - { - return m_s->isLoading(); - } - - virtual bool isSaving() const - { - return m_s->isSaving(); - } - //@} + /// Dtor. + virtual ~ProtectedStream() + { + if( m_autodelete ) { + delete m_s; + } + } - -private: - - Stream * const m_s; - bool const m_autodelete; + /** @name Stream implementation. */ + //@{ + /// Read data. + virtual uint serialize( void * data, uint len ) + { + nvDebugCheck(data != NULL); + len = m_s->serialize( data, len ); -}; + if( m_s->isError() ) { + throw std::exception(); + } + + return len; + } + + virtual void seek( uint pos ) + { + m_s->seek( pos ); + + if( m_s->isError() ) { + throw std::exception(); + } + } + + virtual uint tell() const + { + return m_s->tell(); + } + + virtual uint size() const + { + return m_s->size(); + } + + virtual bool isError() const + { + return m_s->isError(); + } + + virtual void clearError() + { + m_s->clearError(); + } + + virtual bool isAtEnd() const + { + return m_s->isAtEnd(); + } + + virtual bool isSeekable() const + { + return m_s->isSeekable(); + } + + virtual bool isLoading() const + { + return m_s->isLoading(); + } + + virtual bool isSaving() const + { + return m_s->isSaving(); + } + //@} + + + private: + + Stream * const m_s; + bool const m_autodelete; + + }; } // nv namespace diff --git a/src/nvcore/StrLib.cpp b/src/nvcore/StrLib.cpp index a0ee451..605c924 100644 --- a/src/nvcore/StrLib.cpp +++ b/src/nvcore/StrLib.cpp @@ -1,9 +1,9 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio Castaņo #include "StrLib.h" -#include // log -#include // vsnprintf +#include // log +#include // vsnprintf #if NV_CC_MSVC #include // vsnprintf @@ -19,110 +19,110 @@ using namespace nv; namespace { - static char * strAlloc(uint size) - { - return static_cast(mem::malloc(size)); - } - - static char * strReAlloc(char * str, uint size) - { - return static_cast(mem::realloc(str, size)); - } - - static void strFree(const char * str) - { - return mem::free(const_cast(str)); - } - - /*static char * strDup( const char * str ) - { - nvDebugCheck( str != NULL ); - uint len = uint(strlen( str ) + 1); - char * dup = strAlloc( len ); - memcpy( dup, str, len ); - return dup; - }*/ - - // helper function for integer to string conversion. - static char * i2a( uint i, char *a, uint r ) - { - if( i / r > 0 ) { - a = i2a( i / r, a, r ); - } - *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % r]; - return a + 1; - } - - // Locale independent functions. - static inline char toUpper( char c ) { - return (c<'a' || c>'z') ? (c) : (c+'A'-'a'); - } - static inline char toLower( char c ) { - return (c<'A' || c>'Z') ? (c) : (c+'a'-'A'); - } - static inline bool isAlpha( char c ) { - return (c>='a' && c<='z') || (c>='A' && c<='Z'); - } - static inline bool isDigit( char c ) { - return c>='0' && c<='9'; - } - static inline bool isAlnum( char c ) { - return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'); - } - + static char * strAlloc(uint size) + { + return static_cast(mem::malloc(size)); + } + + static char * strReAlloc(char * str, uint size) + { + return static_cast(mem::realloc(str, size)); + } + + static void strFree(const char * str) + { + return mem::free(const_cast(str)); + } + + /*static char * strDup( const char * str ) + { + nvDebugCheck( str != NULL ); + uint len = uint(strlen( str ) + 1); + char * dup = strAlloc( len ); + memcpy( dup, str, len ); + return dup; + }*/ + + // helper function for integer to string conversion. + static char * i2a( uint i, char *a, uint r ) + { + if( i / r > 0 ) { + a = i2a( i / r, a, r ); + } + *a = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[i % r]; + return a + 1; + } + + // Locale independent functions. + static inline char toUpper( char c ) { + return (c<'a' || c>'z') ? (c) : (c+'A'-'a'); + } + static inline char toLower( char c ) { + return (c<'A' || c>'Z') ? (c) : (c+'a'-'A'); + } + static inline bool isAlpha( char c ) { + return (c>='a' && c<='z') || (c>='A' && c<='Z'); + } + static inline bool isDigit( char c ) { + return c>='0' && c<='9'; + } + static inline bool isAlnum( char c ) { + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9'); + } + } int nv::strCmp(const char * s1, const char * s2) { - nvDebugCheck(s1 != NULL); - nvDebugCheck(s2 != NULL); - return strcmp(s1, s2); + nvDebugCheck(s1 != NULL); + nvDebugCheck(s2 != NULL); + return strcmp(s1, s2); } int nv::strCaseCmp(const char * s1, const char * s2) { - nvDebugCheck(s1 != NULL); - nvDebugCheck(s1 != NULL); + nvDebugCheck(s1 != NULL); + nvDebugCheck(s1 != NULL); #if NV_CC_MSVC - return _stricmp(s1, s2); + return _stricmp(s1, s2); #else - return strcasecmp(s1, s2); + return strcasecmp(s1, s2); #endif } void nv::strCpy(char * dst, int size, const char * src) { - nvDebugCheck(dst != NULL); - nvDebugCheck(src != NULL); + nvDebugCheck(dst != NULL); + nvDebugCheck(src != NULL); #if NV_CC_MSVC && _MSC_VER >= 1400 - strcpy_s(dst, size, src); + strcpy_s(dst, size, src); #else - NV_UNUSED(size); - strcpy(dst, src); + NV_UNUSED(size); + strcpy(dst, src); #endif } void nv::strCpy(char * dst, int size, const char * src, int len) { - nvDebugCheck(dst != NULL); - nvDebugCheck(src != NULL); + nvDebugCheck(dst != NULL); + nvDebugCheck(src != NULL); #if NV_CC_MSVC && _MSC_VER >= 1400 - strncpy_s(dst, size, src, len); + strncpy_s(dst, size, src, len); #else - NV_UNUSED(size); - strncpy(dst, src, len); + NV_UNUSED(size); + strncpy(dst, src, len); #endif } void nv::strCat(char * dst, int size, const char * src) { - nvDebugCheck(dst != NULL); - nvDebugCheck(src != NULL); + nvDebugCheck(dst != NULL); + nvDebugCheck(src != NULL); #if NV_CC_MSVC && _MSC_VER >= 1400 - strcat_s(dst, size, src); + strcat_s(dst, size, src); #else - NV_UNUSED(size); - strcat(dst, src); + NV_UNUSED(size); + strcat(dst, src); #endif } @@ -130,8 +130,8 @@ void nv::strCat(char * dst, int size, const char * src) /** Pattern matching routine. I don't remember where did I get this. */ bool nv::strMatch(const char * str, const char * pat) { - nvDebugCheck(str != NULL); - nvDebugCheck(pat != NULL); + nvDebugCheck(str != NULL); + nvDebugCheck(pat != NULL); char c2; @@ -197,311 +197,319 @@ StringBuilder::StringBuilder() : m_size(0), m_str(NULL) /** Preallocate space. */ StringBuilder::StringBuilder( int size_hint ) : m_size(size_hint) { - nvDebugCheck(m_size > 0); - m_str = strAlloc(m_size); - *m_str = '\0'; + nvDebugCheck(m_size > 0); + m_str = strAlloc(m_size); + *m_str = '\0'; } /** Copy ctor. */ StringBuilder::StringBuilder( const StringBuilder & s ) : m_size(0), m_str(NULL) { - copy(s); + copy(s); } /** Copy string. */ -StringBuilder::StringBuilder( const char * s ) : m_size(0), m_str(NULL) +StringBuilder::StringBuilder( const char * s, int extra_size_hint/*=0*/ ) : m_size(0), m_str(NULL) { - copy(s); + copy(s, extra_size_hint); } /** Delete the string. */ StringBuilder::~StringBuilder() { - m_size = 0; - strFree(m_str); - m_str = NULL; + m_size = 0; + strFree(m_str); + m_str = NULL; } /** Format a string safely. */ StringBuilder & StringBuilder::format( const char * fmt, ... ) { - nvDebugCheck(fmt != NULL); - va_list arg; - va_start( arg, fmt ); + nvDebugCheck(fmt != NULL); + va_list arg; + va_start( arg, fmt ); - format( fmt, arg ); + format( fmt, arg ); - va_end( arg ); + va_end( arg ); - return *this; + return *this; } /** Format a string safely. */ StringBuilder & StringBuilder::format( const char * fmt, va_list arg ) { - nvDebugCheck(fmt != NULL); + nvDebugCheck(fmt != NULL); - if( m_size == 0 ) { - m_size = 64; - m_str = strAlloc( m_size ); - } + if( m_size == 0 ) { + m_size = 64; + m_str = strAlloc( m_size ); + } - va_list tmp; - va_copy(tmp, arg); + va_list tmp; + va_copy(tmp, arg); #if NV_CC_MSVC && _MSC_VER >= 1400 - int n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp); + int n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp); #else - int n = vsnprintf(m_str, m_size, fmt, tmp); + int n = vsnprintf(m_str, m_size, fmt, tmp); #endif - va_end(tmp); + va_end(tmp); - while( n < 0 || n >= int(m_size) ) { - if( n > -1 ) { - m_size = n + 1; - } - else { - m_size *= 2; - } + while( n < 0 || n >= int(m_size) ) { + if( n > -1 ) { + m_size = n + 1; + } + else { + m_size *= 2; + } - m_str = strReAlloc(m_str, m_size); + m_str = strReAlloc(m_str, m_size); - va_copy(tmp, arg); + va_copy(tmp, arg); #if NV_CC_MSVC && _MSC_VER >= 1400 - n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp); + n = vsnprintf_s(m_str, m_size, _TRUNCATE, fmt, tmp); #else - n = vsnprintf(m_str, m_size, fmt, tmp); + n = vsnprintf(m_str, m_size, fmt, tmp); #endif - va_end(tmp); - } - - nvDebugCheck(n < int(m_size)); - - // Make sure it's null terminated. - nvDebugCheck(m_str[n] == '\0'); - //str[n] = '\0'; + va_end(tmp); + } - return *this; + nvDebugCheck(n < int(m_size)); + + // Make sure it's null terminated. + nvDebugCheck(m_str[n] == '\0'); + //str[n] = '\0'; + + return *this; } /** Append a string. */ StringBuilder & StringBuilder::append( const char * s ) { - nvDebugCheck(s != NULL); + nvDebugCheck(s != NULL); - const uint slen = uint(strlen( s )); + const uint slen = uint(strlen( s )); - if( m_str == NULL ) { - m_size = slen + 1; - m_str = strAlloc(m_size); - strCpy( m_str, m_size, s ); - } - else { - - const uint len = uint(strlen( m_str )); + if( m_str == NULL ) { + m_size = slen + 1; + m_str = strAlloc(m_size); + strCpy( m_str, m_size, s ); + } + else { - if( m_size < len + slen + 1 ) { - m_size = len + slen + 1; - m_str = strReAlloc(m_str, m_size); - } - - strCat( m_str, m_size, s ); - } + const uint len = uint(strlen( m_str )); - return *this; + if( m_size < len + slen + 1 ) { + m_size = len + slen + 1; + m_str = strReAlloc(m_str, m_size); + } + + strCat( m_str, m_size, s ); + } + + return *this; } /** Append a formatted string. */ StringBuilder & StringBuilder::appendFormat( const char * format, ... ) { - nvDebugCheck( format != NULL ); + nvDebugCheck( format != NULL ); - va_list arg; - va_start( arg, format ); + va_list arg; + va_start( arg, format ); - appendFormat( format, arg ); + appendFormat( format, arg ); - va_end( arg ); + va_end( arg ); - return *this; + return *this; } /** Append a formatted string. */ StringBuilder & StringBuilder::appendFormat( const char * format, va_list arg ) { - nvDebugCheck( format != NULL ); - - va_list tmp; - va_copy(tmp, arg); + nvDebugCheck( format != NULL ); - StringBuilder tmp_str; - tmp_str.format( format, tmp ); - append( tmp_str ); - - va_end(tmp); + va_list tmp; + va_copy(tmp, arg); - return *this; + StringBuilder tmp_str; + tmp_str.format( format, tmp ); + append( tmp_str ); + + va_end(tmp); + + return *this; } /** Convert number to string in the given base. */ StringBuilder & StringBuilder::number( int i, int base ) { - nvCheck( base >= 2 ); - nvCheck( base <= 36 ); + nvCheck( base >= 2 ); + nvCheck( base <= 36 ); - // @@ This needs to be done correctly. - // length = floor(log(i, base)); - uint len = uint(log(float(i)) / log(float(base)) + 2); // one more if negative - reserve(len); + // @@ This needs to be done correctly. + // length = floor(log(i, base)); + uint len = uint(log(float(i)) / log(float(base)) + 2); // one more if negative + reserve(len); - if( i < 0 ) { - *m_str = '-'; - *i2a(uint(-i), m_str+1, base) = 0; - } - else { - *i2a(i, m_str, base) = 0; - } + if( i < 0 ) { + *m_str = '-'; + *i2a(uint(-i), m_str+1, base) = 0; + } + else { + *i2a(i, m_str, base) = 0; + } - return *this; + return *this; } /** Convert number to string in the given base. */ StringBuilder & StringBuilder::number( uint i, int base ) { - nvCheck( base >= 2 ); - nvCheck( base <= 36 ); + nvCheck( base >= 2 ); + nvCheck( base <= 36 ); - // @@ This needs to be done correctly. - // length = floor(log(i, base)); - uint len = uint(log(float(i)) / log(float(base)) - 0.5f + 1); - reserve(len); + // @@ This needs to be done correctly. + // length = floor(log(i, base)); + uint len = uint(log(float(i)) / log(float(base)) - 0.5f + 1); + reserve(len); - *i2a(i, m_str, base) = 0; + *i2a(i, m_str, base) = 0; - return *this; + return *this; } /** Resize the string preserving the contents. */ StringBuilder & StringBuilder::reserve( uint size_hint ) { - nvCheck(size_hint != 0); - if( size_hint > m_size ) { - m_str = strReAlloc(m_str, size_hint); - m_size = size_hint; - } - return *this; + nvCheck(size_hint != 0); + if( size_hint > m_size ) { + m_str = strReAlloc(m_str, size_hint); + m_size = size_hint; + } + return *this; } /** Copy a string safely. */ -StringBuilder & StringBuilder::copy( const char * s ) +StringBuilder & StringBuilder::copy( const char * s, int extra_size/*=0*/ ) { - nvCheck( s != NULL ); - uint str_size = uint(strlen( s )) + 1; - reserve(str_size); - strCpy( m_str, str_size, s ); - return *this; + nvCheck( s != NULL ); + uint str_size = uint(strlen( s )) + 1; + reserve(str_size + extra_size); + strCpy( m_str, str_size, s ); + return *this; } /** Copy an StringBuilder. */ StringBuilder & StringBuilder::copy( const StringBuilder & s ) { - if( s.m_str == NULL ) { - nvCheck( s.m_size == 0 ); - m_size = 0; - strFree( m_str ); - m_str = NULL; - } - else { - reserve( s.m_size ); - strCpy( m_str, s.m_size, s.m_str ); - } - return *this; + if( s.m_str == NULL ) { + nvCheck( s.m_size == 0 ); + m_size = 0; + strFree( m_str ); + m_str = NULL; + } + else { + reserve( s.m_size ); + strCpy( m_str, s.m_size, s.m_str ); + } + return *this; } /** Reset the string. */ void StringBuilder::reset() { - m_size = 0; - strFree( m_str ); - m_str = NULL; + m_size = 0; + strFree( m_str ); + m_str = NULL; } +/** Release the allocated string. */ +char * StringBuilder::release() +{ + char * str = m_str; + m_size = 0; + m_str = NULL; + return str; +} /// Get the file name from a path. const char * Path::fileName() const { - return fileName(m_str); + return fileName(m_str); } /// Get the extension from a file path. const char * Path::extension() const { - return extension(m_str); + return extension(m_str); } /// Toggles path separators (ie. \\ into /). void Path::translatePath() { - nvCheck( m_str != NULL ); + nvCheck( m_str != NULL ); - for(int i = 0; ; i++) { - if( m_str[i] == '\0' ) break; + for(int i = 0; ; i++) { + if( m_str[i] == '\0' ) break; #if NV_PATH_SEPARATOR == '/' - if( m_str[i] == '\\' ) m_str[i] = NV_PATH_SEPARATOR; + if( m_str[i] == '\\' ) m_str[i] = NV_PATH_SEPARATOR; #else - if( m_str[i] == '/' ) m_str[i] = NV_PATH_SEPARATOR; + if( m_str[i] == '/' ) m_str[i] = NV_PATH_SEPARATOR; #endif - } + } } /** - * Strip the file name from a path. - * @warning path cannot end with '/' o '\\', can't it? - */ +* Strip the file name from a path. +* @warning path cannot end with '/' o '\\', can't it? +*/ void Path::stripFileName() { - nvCheck( m_str != NULL ); + nvCheck( m_str != NULL ); - int length = (int)strlen(m_str) - 1; - while (length > 0 && m_str[length] != '/' && m_str[length] != '\\'){ - length--; - } - if( length ) { - m_str[length+1] = 0; - } - else { - m_str[0] = 0; - } + int length = (int)strlen(m_str) - 1; + while (length > 0 && m_str[length] != '/' && m_str[length] != '\\'){ + length--; + } + if( length ) { + m_str[length+1] = 0; + } + else { + m_str[0] = 0; + } } /// Strip the extension from a path name. void Path::stripExtension() { - nvCheck( m_str != NULL ); - - int length = (int)strlen(m_str) - 1; - while( length > 0 && m_str[length] != '.' ) { - length--; - if( m_str[length] == NV_PATH_SEPARATOR ) { - return; // no extension - } - } - if( length ) { - m_str[length] = 0; - } + nvCheck( m_str != NULL ); + + int length = (int)strlen(m_str) - 1; + while( length > 0 && m_str[length] != '.' ) { + length--; + if( m_str[length] == NV_PATH_SEPARATOR ) { + return; // no extension + } + } + if( length ) { + m_str[length] = 0; + } } @@ -509,39 +517,39 @@ void Path::stripExtension() // static char Path::separator() { - return NV_PATH_SEPARATOR; + return NV_PATH_SEPARATOR; } // static const char * Path::fileName(const char * str) { - nvCheck( str != NULL ); + nvCheck( str != NULL ); - int length = (int)strlen(str) - 1; - while( length >= 0 && str[length] != separator() ) { - length--; - } + int length = (int)strlen(str) - 1; + while (length >= 0 && str[length] != '\\' && str[length] != '/') { + length--; + } - return &str[length+1]; + return &str[length+1]; } // static const char * Path::extension(const char * str) { - nvCheck( str != NULL ); + nvCheck( str != NULL ); - int length, l; - l = length = (int)strlen( str ); - while( length > 0 && str[length] != '.' ) { - length--; - if( str[length] == separator() ) { - return &str[l]; // no extension - } - } - if( length == 0 ) { - return &str[l]; - } - return &str[length]; + int length, l; + l = length = (int)strlen( str ); + while (length > 0 && str[length] != '.') { + length--; + if (str[length] != '\\' || str[length] != '/') { + return &str[l]; // no extension + } + } + if (length == 0) { + return &str[l]; + } + return &str[length]; } @@ -549,36 +557,36 @@ const char * Path::extension(const char * str) /// Clone this string String String::clone() const { - String str(data); - return str; + String str(data); + return str; } void String::setString(const char * str) { - if (str == NULL) { - data = NULL; - } - else { - allocString( str ); - addRef(); - } + if (str == NULL) { + data = NULL; + } + else { + allocString( str ); + addRef(); + } } void String::setString(const char * str, int length) { - nvDebugCheck(str != NULL); + nvDebugCheck(str != NULL); - allocString(str, length); - addRef(); + allocString(str, length); + addRef(); } void String::setString(const StringBuilder & str) { - if (str.str() == NULL) { - data = NULL; - } - else { - allocString(str); - addRef(); - } + if (str.str() == NULL) { + data = NULL; + } + else { + allocString(str); + addRef(); + } } diff --git a/src/nvcore/StrLib.h b/src/nvcore/StrLib.h index c20f6b0..f532ac3 100644 --- a/src/nvcore/StrLib.h +++ b/src/nvcore/StrLib.h @@ -1,10 +1,12 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio Castaņo +#pragma once #ifndef NV_CORE_STRING_H #define NV_CORE_STRING_H #include "nvcore.h" -#include "Containers.h" // swap +#include "Memory.h" +#include "Utils.h" // swap, hash #include // strlen, strcmp, etc. @@ -12,343 +14,352 @@ namespace nv { - uint strHash(const char * str, uint h) NV_PURE; + uint strHash(const char * str, uint h) NV_PURE; - /// String hash based on Bernstein's hash. - inline uint strHash(const char * data, uint h = 5381) - { - uint i = 0; - while(data[i] != 0) { - h = (33 * h) ^ uint(data[i]); - i++; - } - return h; - } - - template <> struct hash { - uint operator()(const char * str) const { return strHash(str); } - }; - - 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 void strCpy(char * dst, int size, const char * src); - NVCORE_API void strCpy(char * dst, int size, const char * src, int len); - NVCORE_API void strCat(char * dst, int size, const char * src); + /// String hash based on Bernstein's hash. + inline uint strHash(const char * data, uint h = 5381) + { + uint i = 0; + while(data[i] != 0) { + h = (33 * h) ^ uint(data[i]); + i++; + } + return h; + } - NVCORE_API bool strMatch(const char * str, const char * pat) NV_PURE; - - - /// String builder. - class NVCORE_CLASS StringBuilder - { - public: - - StringBuilder(); - explicit StringBuilder( int size_hint ); - StringBuilder( const char * str ); - StringBuilder( const StringBuilder & ); - - ~StringBuilder(); - - StringBuilder & format( const char * format, ... ) __attribute__((format (printf, 2, 3))); - StringBuilder & format( const char * format, va_list arg ); - - StringBuilder & append( const char * str ); - StringBuilder & appendFormat( const char * format, ... ) __attribute__((format (printf, 2, 3))); - StringBuilder & appendFormat( const char * format, va_list arg ); - - StringBuilder & number( int i, int base = 10 ); - StringBuilder & number( uint i, int base = 10 ); - - StringBuilder & reserve( uint size_hint ); - StringBuilder & copy( const char * str ); - StringBuilder & copy( const StringBuilder & str ); - - StringBuilder & toLower(); - StringBuilder & toUpper(); - - void reset(); - bool isNull() const { return m_size == 0; } - - // const char * accessors - operator const char * () const { return m_str; } - operator char * () { return m_str; } - const char * str() const { return m_str; } - char * str() { return m_str; } - - /// Implement value semantics. - StringBuilder & operator=( const StringBuilder & s ) { - return copy(s); - } - - /// Implement value semantics. - StringBuilder & operator=( const char * s ) { - return copy(s); - } - - /// Equal operator. - bool operator==( const StringBuilder & s ) const { - if (s.isNull()) return isNull(); - else if (isNull()) return false; - else return strcmp(s.m_str, m_str) != 0; - } - - /// Return the exact length. - uint length() const { return isNull() ? 0 : uint(strlen(m_str)); } - - /// Return the size of the string container. - uint capacity() const { return m_size; } - - /// Return the hash of the string. - uint hash() const { return isNull() ? 0 : strHash(m_str); } - - /// Swap strings. - friend void swap(StringBuilder & a, StringBuilder & b) { - nv::swap(a.m_size, b.m_size); - nv::swap(a.m_str, b.m_str); - } - - protected: - - /// Size of the string container. - uint m_size; - - /// String. - char * m_str; - - }; + template <> struct Hash { + uint operator()(const char * str) const { return strHash(str); } + }; - /// Path string. @@ This should be called PathBuilder. - class NVCORE_CLASS Path : public StringBuilder - { - public: - Path() : StringBuilder() {} - explicit Path(int size_hint) : StringBuilder(size_hint) {} - Path(const char * str) : StringBuilder(str) {} - Path(const Path & path) : StringBuilder(path) {} - - const char * fileName() const; - const char * extension() const; - - void translatePath(); - - void stripFileName(); - void stripExtension(); + NVCORE_API int strCaseCmp(const char * s1, const char * s2) NV_PURE; + NVCORE_API int strCmp(const char * s1, const char * s2) NV_PURE; - // statics - NVCORE_API static char separator(); - NVCORE_API static const char * fileName(const char *); - NVCORE_API static const char * extension(const char *); - }; - - - /// String class. - class NVCORE_CLASS String - { - public: + template <> struct Equal { + bool operator()(const char * a, const char * b) const { return strCmp(a, b) == 0; } + }; - /// Constructs a null string. @sa isNull() - String() - { - data = NULL; - } - /// Constructs a shared copy of str. - String(const String & str) - { - data = str.data; - if (data != NULL) addRef(); - } + NVCORE_API void strCpy(char * dst, int size, const char * src); + NVCORE_API void strCpy(char * dst, int size, const char * src, int len); + NVCORE_API void strCat(char * dst, int size, const char * src); - /// Constructs a shared string from a standard string. - String(const char * str) - { - setString(str); - } + NVCORE_API bool strMatch(const char * str, const char * pat) NV_PURE; - /// Constructs a shared string from a standard string. - String(const char * str, int length) - { - setString(str, length); - } - /// Constructs a shared string from a StringBuilder. - String(const StringBuilder & str) - { - setString(str); - } + /// String builder. + class NVCORE_CLASS StringBuilder + { + public: - /// Dtor. - ~String() - { - release(); - } + StringBuilder(); + explicit StringBuilder( int size_hint ); + StringBuilder( const char * str, int extra_size_hint = 0); + StringBuilder( const StringBuilder & ); - String clone() const; - - /// Release the current string and allocate a new one. - const String & operator=( const char * str ) - { - release(); - setString( str ); - return *this; - } + ~StringBuilder(); - /// Release the current string and allocate a new one. - const String & operator=( const StringBuilder & str ) - { - release(); - setString( str ); - return *this; - } - - /// Implement value semantics. - String & operator=( const String & str ) - { - if (str.data != data) - { - release(); - data = str.data; - addRef(); - } - return *this; - } + StringBuilder & format( const char * format, ... ) __attribute__((format (printf, 2, 3))); + StringBuilder & format( const char * format, va_list arg ); - /// Equal operator. - bool operator==( const String & str ) const - { - if( str.data == data ) { - return true; - } - if ((data == NULL) != (str.data == NULL)) { - return false; - } - return strcmp(data, str.data) == 0; - } + StringBuilder & append( const char * str ); + StringBuilder & appendFormat( const char * format, ... ) __attribute__((format (printf, 2, 3))); + StringBuilder & appendFormat( const char * format, va_list arg ); - /// Equal operator. - bool operator==( const char * str ) const - { - nvCheck(str != NULL); // Use isNull! - if (data == NULL) { - return false; - } - return strcmp(data, str) == 0; - } + StringBuilder & number( int i, int base = 10 ); + StringBuilder & number( uint i, int base = 10 ); - /// Not equal operator. - bool operator!=( const String & str ) const - { - if( str.data == data ) { - return false; - } - if ((data == NULL) != (str.data == NULL)) { - return true; - } - return strcmp(data, str.data) != 0; - } - - /// Not equal operator. - bool operator!=( const char * str ) const - { - nvCheck(str != NULL); // Use isNull! - if (data == NULL) { - return false; - } - return strcmp(data, str) != 0; - } - - /// Returns true if this string is the null string. - bool isNull() const { return data == NULL; } - - /// Return the exact length. - uint length() const { nvDebugCheck(data != NULL); return uint(strlen(data)); } - - /// Return the hash of the string. - uint hash() const { nvDebugCheck(data != NULL); return strHash(data); } - - /// const char * cast operator. - operator const char * () const { return data; } - - /// Get string pointer. - const char * str() const { return data; } - + StringBuilder & reserve( uint size_hint ); + StringBuilder & copy( const char * str, int extra_size/*=0*/ ); + StringBuilder & copy( const StringBuilder & str ); - private: + StringBuilder & toLower(); + StringBuilder & toUpper(); - // Add reference count. - void addRef() - { - if (data != NULL) - { - setRefCount(getRefCount() + 1); - } - } - - // Decrease reference count. - void release() - { - if (data != NULL) - { - const uint16 count = getRefCount(); - setRefCount(count - 1); - if (count - 1 == 0) { - mem::free(data - 2); - data = NULL; - } - } - } - - uint16 getRefCount() const - { - nvDebugCheck(data != NULL); - return *reinterpret_cast(data - 2); - } - - void setRefCount(uint16 count) { - nvDebugCheck(data != NULL); - nvCheck(count < 0xFFFF); - *reinterpret_cast(const_cast(data - 2)) = uint16(count); - } - - void setData(const char * str) { - data = str + 2; - } - - void allocString(const char * str) - { - allocString(str, (int)strlen(str)); - } + void reset(); + bool isNull() const { return m_size == 0; } - void allocString(const char * str, int len) - { - const char * ptr = static_cast(mem::malloc(2 + len + 1)); - - setData( ptr ); - setRefCount( 0 ); - - // Copy string. - strCpy(const_cast(data), len+1, str, len); + // const char * accessors + operator const char * () const { return m_str; } + operator char * () { return m_str; } + const char * str() const { return m_str; } + char * str() { return m_str; } - // Add terminating character. - const_cast(data)[len] = '\0'; - } - - void setString(const char * str); - void setString(const char * str, int length); - void setString(const StringBuilder & str); - - /// Swap strings. - friend void swap(String & a, String & b) { - swap(a.data, b.data); - } - - private: + char * release(); - const char * data; - - }; + /// Implement value semantics. + StringBuilder & operator=( const StringBuilder & s ) { + return copy(s); + } + + /// Implement value semantics. + StringBuilder & operator=( const char * s ) { + return copy(s); + } + + /// Equal operator. + bool operator==( const StringBuilder & s ) const { + if (s.isNull()) return isNull(); + else if (isNull()) return false; + else return strcmp(s.m_str, m_str) != 0; + } + + /// Return the exact length. + uint length() const { return isNull() ? 0 : uint(strlen(m_str)); } + + /// Return the size of the string container. + uint capacity() const { return m_size; } + + /// Return the hash of the string. + uint hash() const { return isNull() ? 0 : strHash(m_str); } + + /// Swap strings. + friend void swap(StringBuilder & a, StringBuilder & b) { + nv::swap(a.m_size, b.m_size); + nv::swap(a.m_str, b.m_str); + } + + protected: + + /// Size of the string container. + uint m_size; + + /// String. + char * m_str; + + }; + + + /// Path string. @@ This should be called PathBuilder. + class NVCORE_CLASS Path : public StringBuilder + { + public: + Path() : StringBuilder() {} + explicit Path(int size_hint) : StringBuilder(size_hint) {} + Path(const char * str, int extra_size_hint = 0) : StringBuilder(str, extra_size_hint) {} + Path(const Path & path) : StringBuilder(path) {} + + const char * fileName() const; + const char * extension() const; + + void translatePath(); + + void stripFileName(); + void stripExtension(); + + // statics + NVCORE_API static char separator(); + NVCORE_API static const char * fileName(const char *); + NVCORE_API static const char * extension(const char *); + }; + + + /// String class. + class NVCORE_CLASS String + { + public: + + /// Constructs a null string. @sa isNull() + String() + { + data = NULL; + } + + /// Constructs a shared copy of str. + String(const String & str) + { + data = str.data; + if (data != NULL) addRef(); + } + + /// Constructs a shared string from a standard string. + String(const char * str) + { + setString(str); + } + + /// Constructs a shared string from a standard string. + String(const char * str, int length) + { + setString(str, length); + } + + /// Constructs a shared string from a StringBuilder. + String(const StringBuilder & str) + { + setString(str); + } + + /// Dtor. + ~String() + { + release(); + } + + String clone() const; + + /// Release the current string and allocate a new one. + const String & operator=( const char * str ) + { + release(); + setString( str ); + return *this; + } + + /// Release the current string and allocate a new one. + const String & operator=( const StringBuilder & str ) + { + release(); + setString( str ); + return *this; + } + + /// Implement value semantics. + String & operator=( const String & str ) + { + if (str.data != data) + { + release(); + data = str.data; + addRef(); + } + return *this; + } + + /// Equal operator. + bool operator==( const String & str ) const + { + if( str.data == data ) { + return true; + } + if ((data == NULL) != (str.data == NULL)) { + return false; + } + return strcmp(data, str.data) == 0; + } + + /// Equal operator. + bool operator==( const char * str ) const + { + nvCheck(str != NULL); // Use isNull! + if (data == NULL) { + return false; + } + return strcmp(data, str) == 0; + } + + /// Not equal operator. + bool operator!=( const String & str ) const + { + if( str.data == data ) { + return false; + } + if ((data == NULL) != (str.data == NULL)) { + return true; + } + return strcmp(data, str.data) != 0; + } + + /// Not equal operator. + bool operator!=( const char * str ) const + { + nvCheck(str != NULL); // Use isNull! + if (data == NULL) { + return false; + } + return strcmp(data, str) != 0; + } + + /// Returns true if this string is the null string. + bool isNull() const { return data == NULL; } + + /// Return the exact length. + uint length() const { nvDebugCheck(data != NULL); return uint(strlen(data)); } + + /// Return the hash of the string. + uint hash() const { nvDebugCheck(data != NULL); return strHash(data); } + + /// const char * cast operator. + operator const char * () const { return data; } + + /// Get string pointer. + const char * str() const { return data; } + + + private: + + // Add reference count. + void addRef() + { + if (data != NULL) + { + setRefCount(getRefCount() + 1); + } + } + + // Decrease reference count. + void release() + { + if (data != NULL) + { + const uint16 count = getRefCount(); + setRefCount(count - 1); + if (count - 1 == 0) { + mem::free(data - 2); + data = NULL; + } + } + } + + uint16 getRefCount() const + { + nvDebugCheck(data != NULL); + return *reinterpret_cast(data - 2); + } + + void setRefCount(uint16 count) { + nvDebugCheck(data != NULL); + nvCheck(count < 0xFFFF); + *reinterpret_cast(const_cast(data - 2)) = uint16(count); + } + + void setData(const char * str) { + data = str + 2; + } + + void allocString(const char * str) + { + allocString(str, (int)strlen(str)); + } + + void allocString(const char * str, int len) + { + const char * ptr = static_cast(mem::malloc(2 + len + 1)); + + setData( ptr ); + setRefCount( 0 ); + + // Copy string. + strCpy(const_cast(data), len+1, str, len); + + // Add terminating character. + const_cast(data)[len] = '\0'; + } + + void setString(const char * str); + void setString(const char * str, int length); + void setString(const StringBuilder & str); + + /// Swap strings. + friend void swap(String & a, String & b) { + swap(a.data, b.data); + } + + private: + + const char * data; + + }; } // nv namespace diff --git a/src/nvcore/Stream.h b/src/nvcore/Stream.h index 11a88a6..30cc618 100644 --- a/src/nvcore/Stream.h +++ b/src/nvcore/Stream.h @@ -1,5 +1,6 @@ -// This code is in the public domain -- castano@gmail.com +// This code is in the public domain -- Ignacio Castaņo +#pragma once #ifndef NV_CORE_STREAM_H #define NV_CORE_STREAM_H @@ -9,151 +10,151 @@ namespace nv { - /// Base stream class. - class NVCORE_CLASS Stream { - public: + /// Base stream class. + class NVCORE_CLASS Stream { + public: - enum ByteOrder { - LittleEndian = false, - BigEndian = true, - }; + enum ByteOrder { + LittleEndian = false, + BigEndian = true, + }; - /// Get the byte order of the system. - static ByteOrder getSystemByteOrder() { - #if NV_LITTLE_ENDIAN - return LittleEndian; - #else - return BigEndian; - #endif - } + /// Get the byte order of the system. + static ByteOrder getSystemByteOrder() { +#if NV_LITTLE_ENDIAN + return LittleEndian; +#else + return BigEndian; +#endif + } - /// Ctor. - Stream() : m_byteOrder(LittleEndian) { } + /// Ctor. + Stream() : m_byteOrder(LittleEndian) { } - /// Virtual destructor. - virtual ~Stream() {} + /// Virtual destructor. + virtual ~Stream() {} - /// Set byte order. - void setByteOrder(ByteOrder bo) { m_byteOrder = bo; } - - /// Get byte order. - ByteOrder byteOrder() const { return m_byteOrder; } + /// Set byte order. + void setByteOrder(ByteOrder bo) { m_byteOrder = bo; } - - /// Serialize the given data. - virtual uint serialize( void * data, uint len ) = 0; - - /// Move to the given position in the archive. - virtual void seek( uint pos ) = 0; - - /// Return the current position in the archive. - virtual uint tell() const = 0; - - /// Return the current size of the archive. - virtual uint size() const = 0; - - /// Determine if there has been any error. - virtual bool isError() const = 0; - - /// Clear errors. - virtual void clearError() = 0; - - /// Return true if the stream is at the end. - virtual bool isAtEnd() const = 0; - - /// Return true if the stream is seekable. - virtual bool isSeekable() const = 0; - - /// Return true if this is an input stream. - virtual bool isLoading() const = 0; - - /// Return true if this is an output stream. - virtual bool isSaving() const = 0; - - - // friends - friend Stream & operator<<( Stream & s, bool & c ) { - #if NV_OS_DARWIN - nvStaticCheck(sizeof(bool) == 4); - uint8 b = c ? 1 : 0; - s.serialize( &b, 1 ); - c = (b == 1); - #else - nvStaticCheck(sizeof(bool) == 1); - s.serialize( &c, 1 ); - #endif - return s; - } - friend Stream & operator<<( Stream & s, char & c ) { - nvStaticCheck(sizeof(char) == 1); - s.serialize( &c, 1 ); - return s; - } - friend Stream & operator<<( Stream & s, uint8 & c ) { - nvStaticCheck(sizeof(uint8) == 1); - s.serialize( &c, 1 ); - return s; - } - friend Stream & operator<<( Stream & s, int8 & c ) { - nvStaticCheck(sizeof(int8) == 1); - s.serialize( &c, 1 ); - return s; - } - friend Stream & operator<<( Stream & s, uint16 & c ) { - nvStaticCheck(sizeof(uint16) == 2); - return s.byteOrderSerialize( &c, 2 ); - } - friend Stream & operator<<( Stream & s, int16 & c ) { - nvStaticCheck(sizeof(int16) == 2); - return s.byteOrderSerialize( &c, 2 ); - } - friend Stream & operator<<( Stream & s, uint32 & c ) { - nvStaticCheck(sizeof(uint32) == 4); - return s.byteOrderSerialize( &c, 4 ); - } - friend Stream & operator<<( Stream & s, int32 & c ) { - nvStaticCheck(sizeof(int32) == 4); - return s.byteOrderSerialize( &c, 4 ); - } - friend Stream & operator<<( Stream & s, uint64 & c ) { - nvStaticCheck(sizeof(uint64) == 8); - return s.byteOrderSerialize( &c, 8 ); - } - friend Stream & operator<<( Stream & s, int64 & c ) { - nvStaticCheck(sizeof(int64) == 8); - return s.byteOrderSerialize( &c, 8 ); - } - friend Stream & operator<<( Stream & s, float & c ) { - nvStaticCheck(sizeof(float) == 4); - return s.byteOrderSerialize( &c, 4 ); - } - friend Stream & operator<<( Stream & s, double & c ) { - nvStaticCheck(sizeof(double) == 8); - return s.byteOrderSerialize( &c, 8 ); - } - - protected: - - /// Serialize in the stream byte order. - Stream & byteOrderSerialize( void * v, uint len ) { - if( m_byteOrder == getSystemByteOrder() ) { - serialize( v, len ); - } - else { - for( uint i = len; i > 0; i-- ) { - serialize( (uint8 *)v + i - 1, 1 ); - } - } - return *this; - } + /// Get byte order. + ByteOrder byteOrder() const { return m_byteOrder; } - private: + /// Serialize the given data. + virtual uint serialize( void * data, uint len ) = 0; - ByteOrder m_byteOrder; + /// Move to the given position in the archive. + virtual void seek( uint pos ) = 0; - }; + /// Return the current position in the archive. + virtual uint tell() const = 0; + + /// Return the current size of the archive. + virtual uint size() const = 0; + + /// Determine if there has been any error. + virtual bool isError() const = 0; + + /// Clear errors. + virtual void clearError() = 0; + + /// Return true if the stream is at the end. + virtual bool isAtEnd() const = 0; + + /// Return true if the stream is seekable. + virtual bool isSeekable() const = 0; + + /// Return true if this is an input stream. + virtual bool isLoading() const = 0; + + /// Return true if this is an output stream. + virtual bool isSaving() const = 0; + + + // friends + friend Stream & operator<<( Stream & s, bool & c ) { +#if NV_OS_DARWIN + nvStaticCheck(sizeof(bool) == 4); + uint8 b = c ? 1 : 0; + s.serialize( &b, 1 ); + c = (b == 1); +#else + nvStaticCheck(sizeof(bool) == 1); + s.serialize( &c, 1 ); +#endif + return s; + } + friend Stream & operator<<( Stream & s, char & c ) { + nvStaticCheck(sizeof(char) == 1); + s.serialize( &c, 1 ); + return s; + } + friend Stream & operator<<( Stream & s, uint8 & c ) { + nvStaticCheck(sizeof(uint8) == 1); + s.serialize( &c, 1 ); + return s; + } + friend Stream & operator<<( Stream & s, int8 & c ) { + nvStaticCheck(sizeof(int8) == 1); + s.serialize( &c, 1 ); + return s; + } + friend Stream & operator<<( Stream & s, uint16 & c ) { + nvStaticCheck(sizeof(uint16) == 2); + return s.byteOrderSerialize( &c, 2 ); + } + friend Stream & operator<<( Stream & s, int16 & c ) { + nvStaticCheck(sizeof(int16) == 2); + return s.byteOrderSerialize( &c, 2 ); + } + friend Stream & operator<<( Stream & s, uint32 & c ) { + nvStaticCheck(sizeof(uint32) == 4); + return s.byteOrderSerialize( &c, 4 ); + } + friend Stream & operator<<( Stream & s, int32 & c ) { + nvStaticCheck(sizeof(int32) == 4); + return s.byteOrderSerialize( &c, 4 ); + } + friend Stream & operator<<( Stream & s, uint64 & c ) { + nvStaticCheck(sizeof(uint64) == 8); + return s.byteOrderSerialize( &c, 8 ); + } + friend Stream & operator<<( Stream & s, int64 & c ) { + nvStaticCheck(sizeof(int64) == 8); + return s.byteOrderSerialize( &c, 8 ); + } + friend Stream & operator<<( Stream & s, float & c ) { + nvStaticCheck(sizeof(float) == 4); + return s.byteOrderSerialize( &c, 4 ); + } + friend Stream & operator<<( Stream & s, double & c ) { + nvStaticCheck(sizeof(double) == 8); + return s.byteOrderSerialize( &c, 8 ); + } + + protected: + + /// Serialize in the stream byte order. + Stream & byteOrderSerialize( void * v, uint len ) { + if( m_byteOrder == getSystemByteOrder() ) { + serialize( v, len ); + } + else { + for( uint i = len; i > 0; i-- ) { + serialize( (uint8 *)v + i - 1, 1 ); + } + } + return *this; + } + + + private: + + ByteOrder m_byteOrder; + + }; } // nv namespace diff --git a/src/nvcore/TextReader.cpp b/src/nvcore/TextReader.cpp index 711cba7..fac55de 100644 --- a/src/nvcore/TextReader.cpp +++ b/src/nvcore/TextReader.cpp @@ -1,4 +1,4 @@ -// This code is in the public domain -- castano@gmail.com +// This code is in the public domain -- Ignacio Castaņo #include "TextReader.h" diff --git a/src/nvcore/TextReader.h b/src/nvcore/TextReader.h index 791f067..b738f52 100644 --- a/src/nvcore/TextReader.h +++ b/src/nvcore/TextReader.h @@ -1,37 +1,39 @@ -// This code is in the public domain -- castano@gmail.com +// This code is in the public domain -- Ignacio Castaņo -#ifndef NV_CORE_TEXTREADER_H -#define NV_CORE_TEXTREADER_H +#pragma once +#ifndef NVCORE_TEXTREADER_H +#define NVCORE_TEXTREADER_H -#include "Containers.h" +#include "nvcore.h" #include "Stream.h" +#include "Array.h" namespace nv { -/// Text reader. -class NVCORE_CLASS TextReader { -public: - - /// Ctor. - TextReader(Stream * stream) : m_stream(stream), m_text(512) { - nvCheck(stream != NULL); - nvCheck(stream->isLoading()); - } - - char peek(); - char read(); - - const char *readToEnd(); + /// Text reader. + class NVCORE_CLASS TextReader { + public: - // Returns a temporary string. - const char * readLine(); + /// Ctor. + TextReader(Stream * stream) : m_stream(stream), m_text(512) { + nvCheck(stream != NULL); + nvCheck(stream->isLoading()); + } -private: - Stream * m_stream; - Array m_text; -}; + char peek(); + char read(); + + const char *readToEnd(); + + // Returns a temporary string. + const char * readLine(); + + private: + Stream * m_stream; + Array m_text; + }; } // nv namespace -#endif // NV_CORE_TEXTREADER_H +#endif // NVCORE_TEXTREADER_H diff --git a/src/nvcore/TextWriter.cpp b/src/nvcore/TextWriter.cpp index 8078d0c..12884cb 100644 --- a/src/nvcore/TextWriter.cpp +++ b/src/nvcore/TextWriter.cpp @@ -1,4 +1,4 @@ -// This code is in the public domain -- castano@gmail.com +// This code is in the public domain -- Ignacio Castaņo #include "TextWriter.h" @@ -7,39 +7,39 @@ using namespace nv; /// Constructor TextWriter::TextWriter(Stream * s) : - s(s), - str(1024) + s(s), + str(1024) { - nvCheck(s != NULL); - nvCheck(s->isSaving()); + nvCheck(s != NULL); + nvCheck(s->isSaving()); } void TextWriter::writeString(const char * str) { - nvDebugCheck(s != NULL); - s->serialize(const_cast(str), (int)strlen(str)); + nvDebugCheck(s != NULL); + s->serialize(const_cast(str), (int)strlen(str)); } void TextWriter::writeString(const char * str, uint len) { - nvDebugCheck(s != NULL); - s->serialize(const_cast(str), len); + nvDebugCheck(s != NULL); + s->serialize(const_cast(str), len); } void TextWriter::write(const char * format, ...) { - va_list arg; - va_start(arg,format); - str.format(format, arg); - writeString(str.str(), str.length()); - va_end(arg); + va_list arg; + va_start(arg,format); + str.format(format, arg); + writeString(str.str(), str.length()); + va_end(arg); } void TextWriter::write(const char * format, va_list arg) { - va_list tmp; - va_copy(tmp, arg); - str.format(format, arg); - writeString(str.str(), str.length()); - va_end(tmp); + va_list tmp; + va_copy(tmp, arg); + str.format(format, arg); + writeString(str.str(), str.length()); + va_end(tmp); } diff --git a/src/nvcore/TextWriter.h b/src/nvcore/TextWriter.h index 4661118..8fde3bb 100644 --- a/src/nvcore/TextWriter.h +++ b/src/nvcore/TextWriter.h @@ -1,64 +1,62 @@ -// This code is in the public domain -- castano@gmail.com +// This code is in the public domain -- Ignacio Castaņo -#ifndef NV_CORE_TEXTWRITER_H -#define NV_CORE_TEXTWRITER_H +#pragma once +#ifndef NVCORE_TEXTWRITER_H +#define NVCORE_TEXTWRITER_H -#include "StrLib.h" +#include "nvcore.h" #include "Stream.h" +#include "StrLib.h" namespace nv { - /// Text writer. - class NVCORE_CLASS TextWriter - { - public: - - TextWriter(Stream * s); - - void writeString(const char * str); - void writeString(const char * str, uint len); - void write(const char * format, ...) __attribute__((format (printf, 2, 3))); - void write(const char * format, va_list arg); - - private: - - Stream * s; - - // Temporary string. - StringBuilder str; - - }; + /// Text writer. + class NVCORE_CLASS TextWriter + { + public: + + TextWriter(Stream * s); + + void writeString(const char * str); + void writeString(const char * str, uint len); + void write(const char * format, ...) __attribute__((format (printf, 2, 3))); + void write(const char * format, va_list arg); + + private: + + Stream * s; + + // Temporary string. + StringBuilder str; + + }; - inline TextWriter & operator<<( TextWriter & tw, int i) - { - tw.write("%d", i); - return tw; - } + inline TextWriter & operator<<( TextWriter & tw, int i) + { + tw.write("%d", i); + return tw; + } - inline TextWriter & operator<<( TextWriter & tw, uint i) - { - tw.write("%u", i); - return tw; - } + inline TextWriter & operator<<( TextWriter & tw, uint i) + { + tw.write("%u", i); + return tw; + } - inline TextWriter & operator<<( TextWriter & tw, float f) - { - tw.write("%f", f); - return tw; - } + inline TextWriter & operator<<( TextWriter & tw, float f) + { + tw.write("%f", f); + return tw; + } - inline TextWriter & operator<<( TextWriter & tw, const char * str) - { - tw.writeString(str); - return tw; - } + inline TextWriter & operator<<( TextWriter & tw, const char * str) + { + tw.writeString(str); + return tw; + } } // nv namespace - - - - #endif // NVCORE_TEXTWRITER_H diff --git a/src/nvcore/Timer.h b/src/nvcore/Timer.h index e4a5de4..a07e984 100644 --- a/src/nvcore/Timer.h +++ b/src/nvcore/Timer.h @@ -1,5 +1,6 @@ // This code is in the public domain -- castano@gmail.com +#pragma once #ifndef NV_CORE_TIMER_H #define NV_CORE_TIMER_H @@ -12,16 +13,16 @@ class NVCORE_CLASS Timer { public: - Timer() {} - - void start() { m_start = clock(); } - void stop() { m_stop = clock(); } + Timer() {} + + void start() { m_start = clock(); } + void stop() { m_stop = clock(); } + + float elapsed() const { return float(m_stop - m_start) / CLOCKS_PER_SEC; } - float elapsed() const { return float(m_stop - m_start) / CLOCKS_PER_SEC; } - private: - clock_t m_start; - clock_t m_stop; + clock_t m_start; + clock_t m_stop; }; #else @@ -34,22 +35,22 @@ private: class NVCORE_CLASS Timer { public: - Timer() { - // get the tick frequency from the OS - QueryPerformanceFrequency((LARGE_INTEGER*) &m_frequency); - } - - void start() { QueryPerformanceCounter((LARGE_INTEGER*) &m_start); } - void stop() { QueryPerformanceCounter((LARGE_INTEGER*) &m_stop); } + Timer() { + // get the tick frequency from the OS + QueryPerformanceFrequency((LARGE_INTEGER*) &m_frequency); + } + + void start() { QueryPerformanceCounter((LARGE_INTEGER*) &m_start); } + void stop() { QueryPerformanceCounter((LARGE_INTEGER*) &m_stop); } + + int elapsed() const { + return (int)1000 * ((double)m_stop.QuadPart - (double)m_start.QuadPart) / (double)m_frequency.QuadPart; + } - int elapsed() const { - return (int)1000 * ((double)m_stop.QuadPart - (double)m_start.QuadPart) / (double)m_frequency.QuadPart; - } - private: - LARGE_INTEGER m_frequency; - LARGE_INTEGER m_start; - LARGE_INTEGER m_stop; + LARGE_INTEGER m_frequency; + LARGE_INTEGER m_start; + LARGE_INTEGER m_stop; }; diff --git a/src/nvcore/Utils.h b/src/nvcore/Utils.h new file mode 100644 index 0000000..05e59c5 --- /dev/null +++ b/src/nvcore/Utils.h @@ -0,0 +1,134 @@ +// This code is in the public domain -- Ignacio Castaņo + +#pragma once +#ifndef NV_CORE_UTILS_H +#define NV_CORE_UTILS_H + +#include "nvcore.h" +#include "Debug.h" // nvDebugCheck + +namespace nv +{ + + /// Swap two values. + template + inline void swap(T & a, T & b) + { + T temp = a; + a = b; + b = temp; + } + + /// Return the maximum of the two arguments. + template + inline const T & max(const T & a, const T & b) + { + //return std::max(a, b); + if( a < b ) { + return b; + } + return a; + } + + /// Return the maximum of the three arguments. + template + inline const T & max(const T & a, const T & b, const T & c) + { + return max(a, max(b, c)); + } + + /// Return the minimum of two values. + template + inline const T & min(const T & a, const T & b) + { + //return std::min(a, b); + if( b < a ) { + return b; + } + return a; + } + + /// Return the maximum of the three arguments. + template + inline const T & min(const T & a, const T & b, const T & c) + { + return min(a, min(b, c)); + } + + /// Clamp between two values. + template + inline const T & clamp(const T & x, const T & a, const T & b) + { + return min(max(x, a), b); + } + + /** Return the next power of two. + * @see http://graphics.stanford.edu/~seander/bithacks.html + * @warning Behaviour for 0 is undefined. + * @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x + * @note nextPowerOfTwo(x) = 2 << log2(x-1) + */ + inline uint nextPowerOfTwo( uint x ) + { + nvDebugCheck( x != 0 ); +#if 1 // On modern CPUs this is supposed to be as fast as using the bsr instruction. + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + return x+1; +#else + uint p = 1; + while( x > p ) { + p += p; + } + return p; +#endif + } + + /// Return true if @a n is a power of two. + inline bool isPowerOfTwo( uint n ) + { + return (n & (n-1)) == 0; + } + + + // Some hash functors: + template struct Hash + { + inline uint sdbm_hash(const void * data_in, uint size, uint h = 5381) const + { + const uint8 * data = (const uint8 *) data_in; + uint i = 0; + while (i < size) { + h = (h << 16) + (h << 6) - h + (uint) data[i++]; + } + return h; + } + + uint operator()(const Key & k) const { + return sdbm_hash(&k, sizeof(Key)); + } + }; + template <> struct Hash + { + uint operator()(int x) const { return x; } + }; + template <> struct Hash + { + uint operator()(uint x) const { return x; } + }; + + template struct Equal + { + bool operator()(const Key & k0, const Key & k1) const { + return k0 == k1; + } + }; + + +} // nv namespace + +#endif // NV_CORE_UTILS_H diff --git a/src/nvcore/nvcore.h b/src/nvcore/nvcore.h index 92a34b0..d0adab8 100644 --- a/src/nvcore/nvcore.h +++ b/src/nvcore/nvcore.h @@ -1,5 +1,6 @@ -// This code is in the public domain -- castanyo@yahoo.es +// This code is in the public domain -- Ignacio Castaņo +#pragma once #ifndef NV_CORE_H #define NV_CORE_H @@ -33,7 +34,7 @@ // NV_OS_UNIX // NV_OS_DARWIN -#define NV_OS_STRING POSH_OS_STRING +#define NV_OS_STRING POSH_OS_STRING #if defined POSH_OS_LINUX # define NV_OS_LINUX 1 @@ -59,22 +60,21 @@ # error "Unsupported OS" #endif - // CPUs: // NV_CPU_X86 // NV_CPU_X86_64 // NV_CPU_PPC -#define NV_CPU_STRING POSH_CPU_STRING +#define NV_CPU_STRING POSH_CPU_STRING #if defined POSH_CPU_X86_64 -# define NV_CPU_X86_64 1 +# define NV_CPU_X86_64 1 #elif defined POSH_CPU_X86 -# define NV_CPU_X86 1 +# define NV_CPU_X86 1 #elif defined POSH_CPU_PPC -# define NV_CPU_PPC 1 +# define NV_CPU_PPC 1 #else -# error "Unsupported CPU" +# error "Unsupported CPU" #endif @@ -86,26 +86,26 @@ // @@ NV_CC_MSVC8 #if defined POSH_COMPILER_GCC -# define NV_CC_GNUC 1 -# define NV_CC_STRING "gcc" +# define NV_CC_GNUC 1 +# define NV_CC_STRING "gcc" #elif defined POSH_COMPILER_MSVC -# define NV_CC_MSVC 1 -# define NV_CC_STRING "msvc" +# define NV_CC_MSVC 1 +# define NV_CC_STRING "msvc" #else -# error "Unsupported compiler" +# error "Unsupported compiler" #endif // Endiannes: -#define NV_LITTLE_ENDIAN POSH_LITTLE_ENDIAN -#define NV_BIG_ENDIAN POSH_BIG_ENDIAN -#define NV_ENDIAN_STRING POSH_ENDIAN_STRING +#define NV_LITTLE_ENDIAN POSH_LITTLE_ENDIAN +#define NV_BIG_ENDIAN POSH_BIG_ENDIAN +#define NV_ENDIAN_STRING POSH_ENDIAN_STRING // Version string: #define NV_VERSION_STRING \ - NV_OS_STRING "/" NV_CC_STRING "/" NV_CPU_STRING"/" \ - NV_ENDIAN_STRING"-endian - " __DATE__ "-" __TIME__ + NV_OS_STRING "/" NV_CC_STRING "/" NV_CPU_STRING"/" \ + NV_ENDIAN_STRING"-endian - " __DATE__ "-" __TIME__ /// Disable copy constructor and assignment operator. @@ -120,9 +120,9 @@ /// See Prohibiting Heap-Based Objects in More Effective C++. /// @hideinitializer #define NV_FORBID_HEAPALLOC() \ - private: \ - static void *operator new(size_t size); \ - static void *operator new[](size_t size); + private: \ + static void *operator new(size_t size); \ + static void *operator new[](size_t size); // String concatenation macros. #define NV_STRING_JOIN2(arg1, arg2) NV_DO_STRING_JOIN2(arg1, arg2) @@ -139,12 +139,12 @@ // Startup initialization macro. #define NV_AT_STARTUP(some_code) \ - namespace { \ - static struct NV_STRING_JOIN2(AtStartup_, __LINE__) { \ - NV_STRING_JOIN2(AtStartup_, __LINE__)() { some_code; } \ - } \ - NV_STRING_JOIN3(AtStartup_, __LINE__, Instance); \ - }; + namespace { \ + static struct NV_STRING_JOIN2(AtStartup_, __LINE__) { \ + NV_STRING_JOIN2(AtStartup_, __LINE__)() { some_code; } \ + } \ + NV_STRING_JOIN3(AtStartup_, __LINE__, Instance); \ + }; /// Indicate the compiler that the parameter is not used to suppress compier warnings. /// @hideinitializer @@ -160,23 +160,23 @@ // Platform includes #if NV_CC_MSVC -# if NV_OS_WIN32 -# include "DefsVcWin32.h" -# else -# error "MSVC: Platform not supported" -# endif +# if NV_OS_WIN32 +# include "DefsVcWin32.h" +# else +# error "MSVC: Platform not supported" +# endif #elif NV_CC_GNUC -# if NV_OS_LINUX -# include "DefsGnucLinux.h" -# elif NV_OS_DARWIN || NV_OS_FREEBSD -# include "DefsGnucDarwin.h" -# elif NV_OS_MINGW -# include "DefsGnucWin32.h" -# elif NV_OS_CYGWIN -# error "GCC: Cygwin not supported" -# else -# error "GCC: Platform not supported" -# endif +# if NV_OS_LINUX +# include "DefsGnucLinux.h" +# elif NV_OS_DARWIN || NV_OS_FREEBSD +# include "DefsGnucDarwin.h" +# elif NV_OS_MINGW +# include "DefsGnucWin32.h" +# elif NV_OS_CYGWIN +# error "GCC: Cygwin not supported" +# else +# error "GCC: Platform not supported" +# endif #endif #endif // NV_CORE_H