Merge private branch.

This commit is contained in:
castano
2010-05-27 23:18:08 +00:00
parent 56401d5f7d
commit e7f2d1e2bc
27 changed files with 3429 additions and 3263 deletions

View File

@ -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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
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 <typename T, template <typename T> class C>
void sort(C<T> & container)
{
introsortLoop(container, 0, container.count());
insertionSort(container, 0, container.count());
}
template <typename T, template <typename T> class C>
void sort(C<T> & container, uint begin, uint end)
{
if (begin < end)
{
introsortLoop(container, begin, end);
insertionSort(container, begin, end);
}
}
template <typename T, template <typename T> class C>
void insertionSort(C<T> & container)
{
insertionSort(container, 0, container.count());
}
template <typename T, template <typename T> class C>
void insertionSort(C<T> & 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 <typename T, template <typename T> class C>
void introsortLoop(C<T> & 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 <typename T, template <typename T> class C>
uint partition(C<T> & 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 <typename T, template <typename T> class C>
const T & medianof3(C<T> & 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

525
src/nvcore/Array.h Normal file
View File

@ -0,0 +1,525 @@
// This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#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 <string.h> // memmove
#include <new> // 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 <typename T>
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> typename T::PseudoIndex & operator()(const T * container) {
return *reinterpret_cast<typename T::PseudoIndex *>(memory);
}
template <typename T> const typename T::PseudoIndex & operator()(const T * container) const {
return *reinterpret_cast<const typename T::PseudoIndex *>(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 <typename T>
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<typename T>
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<T> & 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<T> & 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<T> & operator=( const Array<T> & a )
{
copy(a.m_buffer, a.m_size);
return *this;
}
/// Array serialization.
friend Stream & operator<< ( Stream & s, Array<T> & 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<T> & a, Array<T> & 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

View File

@ -2,8 +2,8 @@ PROJECT(nvcore)
SET(CORE_SRCS SET(CORE_SRCS
nvcore.h nvcore.h
Algorithms.h Utils.h
Containers.h Array.h HashMap.h
Debug.h Debug.cpp Debug.h Debug.cpp
DefsGnucDarwin.h DefsGnucDarwin.h
DefsGnucLinux.h DefsGnucLinux.h
@ -13,7 +13,7 @@ SET(CORE_SRCS
Library.h Library.cpp Library.h Library.cpp
Memory.h Memory.cpp Memory.h Memory.cpp
Ptr.h Ptr.h
RefCounted.h RefCounted.cpp RefCounted.h
StrLib.h StrLib.cpp StrLib.h StrLib.cpp
Stream.h Stream.h
StdStream.h StdStream.h

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#include "Debug.h" #include "Debug.h"
#include "StrLib.h" #include "StrLib.h"
@ -13,11 +13,11 @@
# include <crtdbg.h> # include <crtdbg.h>
# if _MSC_VER < 1300 # if _MSC_VER < 1300
# define DECLSPEC_DEPRECATED # define DECLSPEC_DEPRECATED
// VC6: change this path to your Platform SDK headers // VC6: change this path to your Platform SDK headers
# include <dbghelp.h> // must be XP version of file # include <dbghelp.h> // must be XP version of file
// include "M:\\dev7\\vs\\devtools\\common\\win32sdk\\include\\dbghelp.h" // include "M:\\dev7\\vs\\devtools\\common\\win32sdk\\include\\dbghelp.h"
# else # else
// VC7: ships with updated headers // VC7: ships with updated headers
# include <dbghelp.h> # include <dbghelp.h>
# endif # endif
# endif # endif
@ -181,7 +181,7 @@ namespace
static void * callerAddress(void * secret) static void * callerAddress(void * secret)
{ {
# if NV_OS_DARWIN #if NV_OS_DARWIN
# if defined(_STRUCT_MCONTEXT) # if defined(_STRUCT_MCONTEXT)
# if NV_CPU_PPC # if NV_CPU_PPC
ucontext_t * ucp = (ucontext_t *)secret; ucontext_t * ucp = (ucontext_t *)secret;
@ -207,7 +207,7 @@ namespace
ucontext_t * ucp = (ucontext_t *)secret; ucontext_t * ucp = (ucontext_t *)secret;
return (void *)ucp->uc_mcontext.mc_eip; return (void *)ucp->uc_mcontext.mc_eip;
# endif # endif
# else #else
# if NV_CPU_X86_64 # if NV_CPU_X86_64
// #define REG_RIP REG_INDEX(rip) // seems to be 16 // #define REG_RIP REG_INDEX(rip) // seems to be 16
ucontext_t * ucp = (ucontext_t *)secret; ucontext_t * ucp = (ucontext_t *)secret;
@ -219,7 +219,7 @@ namespace
ucontext_t * ucp = (ucontext_t *)secret; ucontext_t * ucp = (ucontext_t *)secret;
return (void *) ucp->uc_mcontext.regs->nip; return (void *) ucp->uc_mcontext.regs->nip;
# endif # endif
# endif #endif
// How to obtain the instruction pointers in different platforms, from mlton's source code. // How to obtain the instruction pointers in different platforms, from mlton's source code.
// http://mlton.org/ // http://mlton.org/
@ -262,7 +262,7 @@ namespace
nvDebug("Got signal %d\n", sig); nvDebug("Got signal %d\n", sig);
} }
# if defined(HAVE_EXECINFO_H) #if defined(HAVE_EXECINFO_H)
if (nvHasStackTrace()) // in case of weak linking if (nvHasStackTrace()) // in case of weak linking
{ {
void * trace[64]; void * trace[64];
@ -275,7 +275,7 @@ namespace
nvPrintStackTrace(trace, size, 1); nvPrintStackTrace(trace, size, 1);
} }
# endif // defined(HAVE_EXECINFO_H) #endif // defined(HAVE_EXECINFO_H)
exit(0); exit(0);
} }
@ -318,7 +318,7 @@ namespace
} }
// Assert handler method. // Assert handler method.
virtual int assert( const char * exp, const char * file, int line, const char * func/*=NULL*/ ) virtual int assertion( const char * exp, const char * file, int line, const char * func/*=NULL*/ )
{ {
int ret = NV_ABORT_EXIT; int ret = NV_ABORT_EXIT;
@ -332,9 +332,7 @@ namespace
nvDebug( error_string ); nvDebug( error_string );
} }
#if _DEBUG if (isDebuggerPresent()) {
if( isDebuggerPresent() ) {
return NV_ABORT_DEBUG; return NV_ABORT_DEBUG;
} }
@ -356,8 +354,6 @@ namespace
return NV_ABORT_DEBUG; return NV_ABORT_DEBUG;
}*/ }*/
#endif
if( ret == NV_ABORT_EXIT ) { if( ret == NV_ABORT_EXIT ) {
// Exit cleanly. // Exit cleanly.
throw std::runtime_error("Assertion failed"); throw std::runtime_error("Assertion failed");
@ -374,7 +370,7 @@ namespace
{ {
bool isDebuggerPresent() bool isDebuggerPresent()
{ {
# if NV_OS_DARWIN #if NV_OS_DARWIN
int mib[4]; int mib[4];
struct kinfo_proc info; struct kinfo_proc info;
size_t size; size_t size;
@ -386,14 +382,14 @@ namespace
info.kp_proc.p_flag = 0; info.kp_proc.p_flag = 0;
sysctl(mib,4,&info,&size,NULL,0); sysctl(mib,4,&info,&size,NULL,0);
return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED); return ((info.kp_proc.p_flag & P_TRACED) == P_TRACED);
# else #else
// if ppid != sid, some process spawned our app, probably a debugger. // if ppid != sid, some process spawned our app, probably a debugger.
return getsid(getpid()) != getppid(); return getsid(getpid()) != getppid();
# endif #endif
} }
// Assert handler method. // Assert handler method.
virtual int assert(const char * exp, const char * file, int line, const char * func) virtual int assertion(const char * exp, const char * file, int line, const char * func)
{ {
if( func != NULL ) { if( func != NULL ) {
nvDebug( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line ); nvDebug( "*** Assertion failed: %s\n On file: %s\n On function: %s\n On line: %d\n ", exp, file, func, line );
@ -402,20 +398,20 @@ namespace
nvDebug( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line ); nvDebug( "*** Assertion failed: %s\n On file: %s\n On line: %d\n ", exp, file, line );
} }
# if _DEBUG #if _DEBUG
if( isDebuggerPresent() ) { if (isDebuggerPresent()) {
return NV_ABORT_DEBUG; return NV_ABORT_DEBUG;
} }
# endif #endif
# if defined(HAVE_EXECINFO_H) #if defined(HAVE_EXECINFO_H)
if (nvHasStackTrace()) if (nvHasStackTrace())
{ {
void * trace[64]; void * trace[64];
int size = backtrace(trace, 64); int size = backtrace(trace, 64);
nvPrintStackTrace(trace, size, 2); nvPrintStackTrace(trace, size, 2);
} }
# endif #endif
// Exit cleanly. // Exit cleanly.
throw std::runtime_error("Assertion failed"); throw std::runtime_error("Assertion failed");
@ -428,7 +424,7 @@ namespace
/// Handle assertion through the asset handler. /// 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 #if NV_OS_WIN32 //&& NV_CC_MSVC
static Win32AssertHandler s_default_assert_handler; static Win32AssertHandler s_default_assert_handler;
@ -436,21 +432,21 @@ int nvAbort(const char * exp, const char * file, int line, const char * func)
static UnixAssertHandler s_default_assert_handler; static UnixAssertHandler s_default_assert_handler;
#endif #endif
if( s_assert_handler != NULL ) { if (s_assert_handler != NULL) {
return s_assert_handler->assert( exp, file, line, func ); return s_assert_handler->assertion( exp, file, line, func );
} }
else { else {
return s_default_assert_handler.assert( exp, file, line, func ); return s_default_assert_handler.assertion( exp, file, line, func );
} }
} }
/// Shows a message through the message handler. /// 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_list arg;
va_start(arg,msg); va_start(arg,msg);
if( s_message_handler != NULL ) { if (s_message_handler != NULL) {
s_message_handler->log( msg, arg ); s_message_handler->log( msg, arg );
} }
va_end(arg); va_end(arg);

View File

@ -1,5 +1,6 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#pragma once
#ifndef NV_CORE_DEBUG_H #ifndef NV_CORE_DEBUG_H
#define NV_CORE_DEBUG_H #define NV_CORE_DEBUG_H
@ -13,8 +14,6 @@
#define NV_ABORT_IGNORE 2 #define NV_ABORT_IGNORE 2
#define NV_ABORT_EXIT 3 #define NV_ABORT_EXIT 3
#undef assert // avoid conflicts with assert method.
#define nvNoAssert(exp) \ #define nvNoAssert(exp) \
do { \ do { \
(void)sizeof(exp); \ (void)sizeof(exp); \
@ -31,11 +30,11 @@
#else // NV_NO_ASSERT #else // NV_NO_ASSERT
# if NV_CC_MSVC # if NV_CC_MSVC
// @@ Does this work in msvc-6 and earlier? // @@ Does this work in msvc-6 and earlier?
// @@ Do I have to include <intrin.h> ?
# define nvDebugBreak() __debugbreak() # define nvDebugBreak() __debugbreak()
// define nvDebugBreak() __asm int 3 //# define nvDebugBreak() __asm { int 3 }
# elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN # elif NV_CC_GNUC && NV_CPU_PPC && NV_OS_DARWIN
// @@ Use __builtin_trap() on GCC
# define nvDebugBreak() __asm__ volatile ("trap"); # define nvDebugBreak() __asm__ volatile ("trap");
# elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN # elif NV_CC_GNUC && NV_CPU_X86 && NV_OS_DARWIN
# define nvDebugBreak() __asm__ volatile ("int3"); # define nvDebugBreak() __asm__ volatile ("int3");
@ -44,18 +43,36 @@
# else # else
# include <signal.h> # include <signal.h>
# define nvDebugBreak() raise(SIGTRAP); # define nvDebugBreak() raise(SIGTRAP);
// define nvDebugBreak() *((int *)(0)) = 0 // define nvDebugBreak() *((int *)(0)) = 0
# endif # endif
#define nvDebugBreakOnce() \
do { \
static bool firstTime = true; \
if (firstTime) { firstTime = false; nvDebugBreak(); } \
} while(false)
# define nvAssertMacro(exp) \ # define nvAssertMacro(exp) \
do { \ do { \
if(!(exp)) { \ if (!(exp)) { \
if( nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG ) { \ if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \
nvDebugBreak(); \ nvDebugBreak(); \
} \ } \
} \ } \
} while(false) } while(false)
# 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 nvAssert(exp) nvAssertMacro(exp)
# define nvCheck(exp) nvAssertMacro(exp) # define nvCheck(exp) nvAssertMacro(exp)
@ -70,7 +87,7 @@
#endif // NV_NO_ASSERT #endif // NV_NO_ASSERT
// Use nvAssume for very simple expresions only: nvAssume(0), nvAssume(value == true), etc. // Use nvAssume for very simple expresions only: nvAssume(0), nvAssume(value == true), etc.
#if defined(_DEBUG) #if !defined(_DEBUG)
# if NV_CC_MSVC # if NV_CC_MSVC
# define nvAssume(exp) __assume(exp) # define nvAssume(exp) __assume(exp)
# else # else
@ -82,31 +99,57 @@
#define nvError(x) nvAbort(x, __FILE__, __LINE__, __FUNC__) #define nvError(x) nvAbort(x, __FILE__, __LINE__, __FUNC__)
#define nvWarning(x) nvDebug("*** Warning %s/%d: %s\n", __FILE__, __LINE__, (x)) #define nvWarning(x) nvDebugPrint("*** Warning %s/%d: %s\n", __FILE__, __LINE__, (x))
#ifndef NV_DEBUG_PRINT
#if PI_CC_MSVC #define NV_DEBUG_PRINT 1 //defined(_DEBUG)
// @@ 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:; }
#endif #endif
NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = 0); #if NV_DEBUG_PRINT
NVCORE_API void NV_CDECL nvDebug( const char *msg, ... ) __attribute__((format (printf, 1, 2))); #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 namespace nv
{ {
/** Message handler interface. */ inline bool isValidPtr(const void * ptr) {
#if NV_CPU_X86_64
if (ptr == NULL) return true;
if (reinterpret_cast<uint64>(ptr) < 0x10000ULL) return false;
if (reinterpret_cast<uint64>(ptr) >= 0x000007FFFFFEFFFFULL) return false;
#else
if (reinterpret_cast<uint>(ptr) == 0xcccccccc) return false;
if (reinterpret_cast<uint>(ptr) == 0xcdcdcdcd) return false;
if (reinterpret_cast<uint>(ptr) == 0xdddddddd) return false;
if (reinterpret_cast<uint>(ptr) == 0xffffffff) return false;
#endif
return true;
}
/// Message handler interface.
struct MessageHandler { struct MessageHandler {
virtual void log(const char * str, va_list arg) = 0; virtual void log(const char * str, va_list arg) = 0;
virtual ~MessageHandler() {} virtual ~MessageHandler() {}
}; };
/** Assert handler interface. */ /// Assert handler interface.
struct AssertHandler { struct AssertHandler {
virtual int assert(const char *exp, const char *file, int line, const char *func = 0) = 0; virtual int assertion(const char *exp, const char *file, int line, const char *func = NULL) = 0;
virtual ~AssertHandler() {} virtual ~AssertHandler() {}
}; };
@ -115,7 +158,6 @@ namespace nv
{ {
NVCORE_API void dumpInfo(); NVCORE_API void dumpInfo();
// These functions are not thread safe.
NVCORE_API void setMessageHandler( MessageHandler * messageHandler ); NVCORE_API void setMessageHandler( MessageHandler * messageHandler );
NVCORE_API void resetMessageHandler(); NVCORE_API void resetMessageHandler();

View File

@ -1,3 +1,5 @@
// This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#ifndef NV_CORE_H #ifndef NV_CORE_H
#error "Do not include this file directly." #error "Do not include this file directly."
#endif #endif
@ -26,7 +28,9 @@
#define chdir _chdir #define chdir _chdir
#define getcwd _getcwd #define getcwd _getcwd
#define va_copy(a, b) a = b #ifndef va_copy
#define va_copy(a, b) (a) = (b)
#endif
#if !defined restrict #if !defined restrict
#define restrict #define restrict

View File

@ -1,13 +1,13 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- castano@gmail.com
#include "FileSystem.h" #include "FileSystem.h"
#include <nvcore/nvcore.h>
#if NV_OS_WIN32 #if NV_OS_WIN32
#define _CRT_NONSTDC_NO_WARNINGS // _chdir is defined deprecated, but that's a bug, chdir is deprecated, _chdir is *not*. #define _CRT_NONSTDC_NO_WARNINGS // _chdir is defined deprecated, but that's a bug, chdir is deprecated, _chdir is *not*.
//#include <shlwapi.h> // PathFileExists //#include <shlwapi.h> // PathFileExists
#include <windows.h> // GetFileAttributes #include <windows.h> // GetFileAttributes
#include <direct.h> // _mkdir #include <direct.h> // _mkdir
#include <stdio.h> // remove, unlink
#else #else
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -26,7 +26,7 @@ bool FileSystem::exists(const char * path)
#elif NV_OS_WIN32 #elif NV_OS_WIN32
// PathFileExists requires linking to shlwapi.lib // PathFileExists requires linking to shlwapi.lib
//return PathFileExists(path) != 0; //return PathFileExists(path) != 0;
return GetFileAttributes(path) != 0xFFFFFFFF; return GetFileAttributesA(path) != 0xFFFFFFFF;
#else #else
if (FILE * fp = fopen(path, "r")) if (FILE * fp = fopen(path, "r"))
{ {
@ -54,3 +54,9 @@ bool FileSystem::changeDirectory(const char * path)
return chdir(path) != -1; return chdir(path) != -1;
#endif #endif
} }
bool FileSystem::removeFile(const char * path)
{
// @@ Use unlink or remove?
return remove(path) == 0;
}

View File

@ -1,5 +1,6 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- castano@gmail.com
#pragma once
#ifndef NV_CORE_FILESYSTEM_H #ifndef NV_CORE_FILESYSTEM_H
#define NV_CORE_FILESYSTEM_H #define NV_CORE_FILESYSTEM_H
@ -10,10 +11,10 @@ namespace nv
namespace FileSystem namespace FileSystem
{ {
NVCORE_API bool exists(const char * path); NVCORE_API bool exists(const char * path);
NVCORE_API bool createDirectory(const char * path); NVCORE_API bool createDirectory(const char * path);
NVCORE_API bool changeDirectory(const char * path); NVCORE_API bool changeDirectory(const char * path);
NVCORE_API bool removeFile(const char * path);
} // FileSystem namespace } // FileSystem namespace

563
src/nvcore/HashMap.h Normal file
View File

@ -0,0 +1,563 @@
// This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#pragma once
#ifndef NV_CORE_HASHMAP_H
#define NV_CORE_HASHMAP_H
/*
HashMap based on Thatcher Ulrich <tu@tulrich.com> 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 <new> // 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 T, typename U, typename H = Hash<T>, typename E = Equal<T> >
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<T, U, H, E> 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

View File

@ -1,5 +1,6 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- castano@gmail.com
#pragma once
#ifndef NV_CORE_LIBRARY_H #ifndef NV_CORE_LIBRARY_H
#define NV_CORE_LIBRARY_H #define NV_CORE_LIBRARY_H

View File

@ -1,3 +1,4 @@
// This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#include "Memory.h" #include "Memory.h"
#include "Debug.h" #include "Debug.h"

View File

@ -1,5 +1,6 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
#pragma once
#ifndef NV_CORE_MEMORY_H #ifndef NV_CORE_MEMORY_H
#define NV_CORE_MEMORY_H #define NV_CORE_MEMORY_H

View File

@ -1,4 +1,4 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#ifndef NV_CORE_PTR_H #ifndef NV_CORE_PTR_H
#define NV_CORE_PTR_H #define NV_CORE_PTR_H
@ -6,13 +6,13 @@
#include "nvcore.h" #include "nvcore.h"
#include "Debug.h" #include "Debug.h"
#include <stdio.h> // NULL
namespace nv namespace nv
{ {
class WeakProxy;
/** Simple auto pointer template class. /** Simple auto pointer template class.
* *
* This is very similar to the standard auto_ptr class, but with some * This is very similar to the standard auto_ptr class, but with some
* additional limitations to make its use less error prone: * additional limitations to make its use less error prone:
@ -23,12 +23,12 @@ namespace nv
* on the std implementation. For a discussion of the problems of auto_ptr read: * 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 * http://www.awprofessional.com/content/images/020163371X/autoptrupdate\auto_ptr_update.html
*/ */
template <class T> template <class T>
class AutoPtr class AutoPtr
{ {
NV_FORBID_COPY(AutoPtr); NV_FORBID_COPY(AutoPtr);
NV_FORBID_HEAPALLOC(); NV_FORBID_HEAPALLOC();
public: public:
/// Ctor. /// Ctor.
AutoPtr(T * p = NULL) : m_ptr(p) { } AutoPtr(T * p = NULL) : m_ptr(p) { }
@ -36,13 +36,13 @@ public:
template <class Q> template <class Q>
AutoPtr(Q * p) : m_ptr(static_cast<T *>(p)) { } AutoPtr(Q * p) : m_ptr(static_cast<T *>(p)) { }
/** Dtor. Deletes owned pointer. */ /// Dtor. Deletes owned pointer.
~AutoPtr() { ~AutoPtr() {
delete m_ptr; delete m_ptr;
m_ptr = NULL; m_ptr = NULL;
} }
/** Delete owned pointer and assign new one. */ /// Delete owned pointer and assign new one.
void operator=( T * p ) { void operator=( T * p ) {
if (p != m_ptr) if (p != m_ptr)
{ {
@ -60,57 +60,57 @@ public:
} }
} }
/** Member access. */ /// Member access.
T * operator -> () const { T * operator -> () const {
nvDebugCheck(m_ptr != NULL); nvDebugCheck(m_ptr != NULL);
return m_ptr; return m_ptr;
} }
/** Get reference. */ /// Get reference.
T & operator*() const { T & operator*() const {
nvDebugCheck(m_ptr != NULL); nvDebugCheck(m_ptr != NULL);
return *m_ptr; return *m_ptr;
} }
/** Get pointer. */ /// Get pointer.
T * ptr() const { return m_ptr; } T * ptr() const { return m_ptr; }
/** Relinquish ownership of the underlying pointer and returns that pointer. */ /// Relinquish ownership of the underlying pointer and returns that pointer.
T * release() { T * release() {
T * tmp = m_ptr; T * tmp = m_ptr;
m_ptr = NULL; m_ptr = NULL;
return tmp; return tmp;
} }
/** Const pointer equal comparation. */ /// Const pointer equal comparation.
friend bool operator == (const AutoPtr<T> & ap, const T * const p) { friend bool operator == (const AutoPtr<T> & ap, const T * const p) {
return (ap.ptr() == p); return (ap.ptr() == p);
} }
/** Const pointer nequal comparation. */ /// Const pointer nequal comparation.
friend bool operator != (const AutoPtr<T> & ap, const T * const p) { friend bool operator != (const AutoPtr<T> & ap, const T * const p) {
return (ap.ptr() != p); return (ap.ptr() != p);
} }
/** Const pointer equal comparation. */ /// Const pointer equal comparation.
friend bool operator == (const T * const p, const AutoPtr<T> & ap) { friend bool operator == (const T * const p, const AutoPtr<T> & ap) {
return (ap.ptr() == p); return (ap.ptr() == p);
} }
/** Const pointer nequal comparation. */ /// Const pointer nequal comparation.
friend bool operator != (const T * const p, const AutoPtr<T> & ap) { friend bool operator != (const T * const p, const AutoPtr<T> & ap) {
return (ap.ptr() != p); return (ap.ptr() != p);
} }
private: private:
T * m_ptr; T * m_ptr;
}; };
/// Smart pointer template class. /// Smart pointer template class.
template <class BaseClass> template <class BaseClass>
class SmartPtr { class SmartPtr {
public: public:
// BaseClass must implement addRef() and release(). // BaseClass must implement addRef() and release().
typedef SmartPtr<BaseClass> ThisType; typedef SmartPtr<BaseClass> ThisType;
@ -120,152 +120,202 @@ public:
{ {
} }
/** Other type assignment. */ /// Other type assignment.
template <class OtherBase> template <class OtherBase>
SmartPtr( const SmartPtr<OtherBase> & tc ) SmartPtr( const SmartPtr<OtherBase> & tc )
{ {
m_ptr = static_cast<BaseClass *>( tc.ptr() ); m_ptr = static_cast<BaseClass *>( tc.ptr() );
if( m_ptr ) { if (m_ptr) {
m_ptr->addRef(); m_ptr->addRef();
} }
} }
/** Copy ctor. */ /// Copy ctor.
SmartPtr( const ThisType & bc ) SmartPtr( const ThisType & bc )
{ {
m_ptr = bc.ptr(); m_ptr = bc.ptr();
if( m_ptr ) { if (m_ptr) {
m_ptr->addRef(); m_ptr->addRef();
} }
} }
/** Copy cast ctor. SmartPtr(NULL) is valid. */ /// Copy cast ctor. SmartPtr(NULL) is valid.
explicit SmartPtr( BaseClass * bc ) explicit SmartPtr( BaseClass * bc )
{ {
m_ptr = bc; m_ptr = bc;
if( m_ptr ) { if (m_ptr) {
m_ptr->addRef(); m_ptr->addRef();
} }
} }
/** Dtor. */ /// Dtor.
~SmartPtr() ~SmartPtr()
{ {
set(NULL); set(NULL);
} }
/** @name Accessors: */ /// -> operator.
//@{
/** -> operator. */
BaseClass * operator -> () const BaseClass * operator -> () const
{ {
nvCheck( m_ptr != NULL ); nvCheck( m_ptr != NULL );
return m_ptr; return m_ptr;
} }
/** * operator. */ /// * operator.
BaseClass & operator*() const BaseClass & operator*() const
{ {
nvCheck( m_ptr != NULL ); nvCheck( m_ptr != NULL );
return *m_ptr; return *m_ptr;
} }
/** Get pointer. */ /// Get pointer.
BaseClass * ptr() const BaseClass * ptr() const
{ {
return m_ptr; return m_ptr;
} }
//@}
/// Other type assignment.
/** @name Mutators: */
//@{
/** Other type assignment. */
template <class OtherBase> template <class OtherBase>
void operator = ( const SmartPtr<OtherBase> & tc ) void operator = ( const SmartPtr<OtherBase> & tc )
{ {
set( static_cast<BaseClass *>(tc.ptr()) ); set( static_cast<BaseClass *>(tc.ptr()) );
} }
/** This type assignment. */ /// This type assignment.
void operator = ( const ThisType & bc ) void operator = ( const ThisType & bc )
{ {
set( bc.ptr() ); set( bc.ptr() );
} }
/** Pointer assignment. */ /// Pointer assignment.
void operator = ( BaseClass * bc ) void operator = ( BaseClass * bc )
{ {
set( bc ); set( bc );
} }
//@}
/** @name Comparators: */ /// Other type equal comparation.
//@{
/** Other type equal comparation. */
template <class OtherBase> template <class OtherBase>
bool operator == ( const SmartPtr<OtherBase> & other ) const bool operator == ( const SmartPtr<OtherBase> & other ) const
{ {
return m_ptr == other.ptr(); return m_ptr == other.ptr();
} }
/** This type equal comparation. */ /// This type equal comparation.
bool operator == ( const ThisType & bc ) const bool operator == ( const ThisType & bc ) const
{ {
return m_ptr == bc.ptr(); return m_ptr == bc.ptr();
} }
/** Const pointer equal comparation. */ /// Const pointer equal comparation.
bool operator == ( const BaseClass * const bc ) const bool operator == ( const BaseClass * const bc ) const
{ {
return m_ptr == bc; return m_ptr == bc;
} }
/** Other type not equal comparation. */ /// Other type not equal comparation.
template <class OtherBase> template <class OtherBase>
bool operator != ( const SmartPtr<OtherBase> & other ) const bool operator != ( const SmartPtr<OtherBase> & other ) const
{ {
return m_ptr != other.ptr(); return m_ptr != other.ptr();
} }
/** Other type not equal comparation. */ /// Other type not equal comparation.
bool operator != ( const ThisType & bc ) const bool operator != ( const ThisType & bc ) const
{ {
return m_ptr != bc.ptr(); return m_ptr != bc.ptr();
} }
/** Const pointer not equal comparation. */ /// Const pointer not equal comparation.
bool operator != (const BaseClass * const bc) const bool operator != (const BaseClass * const bc) const
{ {
return m_ptr != bc; return m_ptr != bc;
} }
/** This type lower than comparation. */ /// This type lower than comparation.
bool operator < (const ThisType & p) const bool operator < (const ThisType & p) const
{ {
return m_ptr < p.ptr(); return m_ptr < p.ptr();
} }
//@}
private: bool isValid() const {
return isValidPtr(m_ptr);
}
/** Set this pointer. */ private:
// Set this pointer.
void set( BaseClass * p ) void set( BaseClass * p )
{ {
if( m_ptr != p ) { if (p) p->addRef();
if( m_ptr ) m_ptr->release(); if (m_ptr) m_ptr->release();
if( p ) p->addRef();
m_ptr = p; m_ptr = p;
} }
}
private: private:
BaseClass * m_ptr; BaseClass * m_ptr;
}; };
/// Smart pointer template class.
template <class T>
class WeakPtr {
public:
WeakPtr() {}
WeakPtr(T * p) { operator=(p); }
WeakPtr(const SmartPtr<T> & p) { operator=(p.ptr()); }
// Default constructor and assignment from weak_ptr<T> are OK.
void operator=(T * p)
{
if (p) {
m_proxy = p->getWeakProxy();
assert(m_proxy != NULL);
assert(m_proxy->ptr() == p);
}
else {
m_proxy = NULL;
}
}
void operator=(const SmartPtr<T> & ptr) { operator=(ptr.ptr()); }
bool operator==(const SmartPtr<T> & p) const { return ptr() == p.ptr(); }
bool operator!=(const SmartPtr<T> & p) const { return ptr() != p.ptr(); }
bool operator==(const WeakPtr<T> & p) const { return ptr() == p.ptr(); }
bool operator!=(const WeakPtr<T> & p) const { return ptr() != p.ptr(); }
bool operator==(T * p) const { return ptr() == p; }
bool operator!=(T * p) const { return ptr() != p; }
T * operator->() const
{
T * p = ptr();
assert(p != NULL);
return p;
}
T * ptr() const
{
if (m_proxy != NULL) {
return static_cast<T *>(m_proxy->ptr());
}
return NULL;
}
private:
mutable SmartPtr<WeakProxy> m_proxy;
};
} // nv namespace } // nv namespace

View File

@ -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;

View File

@ -1,4 +1,4 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#ifndef NV_CORE_REFCOUNTED_H #ifndef NV_CORE_REFCOUNTED_H
#define NV_CORE_REFCOUNTED_H #define NV_CORE_REFCOUNTED_H
@ -6,9 +6,68 @@
#include "nvcore.h" #include "nvcore.h"
#include "Debug.h" #include "Debug.h"
#define NV_DECLARE_PTR(Class) \
template <class T> class SmartPtr; \
typedef SmartPtr<class Class> Class ## Ptr; \
typedef SmartPtr<const class Class> Class ## ConstPtr
namespace nv namespace nv
{ {
/// Weak proxy.
class WeakProxy
{
NV_FORBID_COPY(WeakProxy);
public:
/// Ctor.
WeakProxy(void * ptr) : m_count(0), m_ptr(ptr) { }
/// Dtor.
~WeakProxy()
{
nvCheck( m_count == 0 );
}
/// Increase reference count.
uint addRef() const
{
m_count++;
return m_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;
};
/// Reference counted base class to be used with SmartPtr and WeakPtr. /// Reference counted base class to be used with SmartPtr and WeakPtr.
class RefCounted class RefCounted
@ -17,24 +76,21 @@ namespace nv
public: public:
/// Ctor. /// Ctor.
RefCounted() : m_count(0)/*, m_weak_proxy(NULL)*/ RefCounted() : m_count(0), m_weak_proxy(NULL)
{ {
s_total_obj_count++;
} }
/// Virtual dtor. /// Virtual dtor.
virtual ~RefCounted() virtual ~RefCounted()
{ {
nvCheck( m_count == 0 ); nvCheck( m_count == 0 );
nvCheck( s_total_obj_count > 0 ); releaseWeakProxy();
s_total_obj_count--;
} }
/// Increase reference count. /// Increase reference count.
uint addRef() const uint addRef() const
{ {
s_total_ref_count++;
m_count++; m_count++;
return m_count; return m_count;
} }
@ -45,22 +101,20 @@ namespace nv
{ {
nvCheck( m_count > 0 ); nvCheck( m_count > 0 );
s_total_ref_count--;
m_count--; m_count--;
if( m_count == 0 ) { if( m_count == 0 ) {
// releaseWeakProxy();
delete this; delete this;
return 0; return 0;
} }
return m_count; return m_count;
} }
/*
/// Get weak proxy. /// Get weak proxy.
WeakProxy * getWeakProxy() const WeakProxy * getWeakProxy() const
{ {
if (m_weak_proxy == NULL) { if (m_weak_proxy == NULL) {
m_weak_proxy = new WeakProxy; m_weak_proxy = new WeakProxy((void *)this);
m_weak_proxy->AddRef(); m_weak_proxy->addRef();
} }
return m_weak_proxy; return m_weak_proxy;
} }
@ -69,45 +123,26 @@ namespace nv
void releaseWeakProxy() const void releaseWeakProxy() const
{ {
if (m_weak_proxy != NULL) { if (m_weak_proxy != NULL) {
m_weak_proxy->NotifyObjectDied(); m_weak_proxy->notifyObjectDied();
m_weak_proxy->Release(); m_weak_proxy->release();
m_weak_proxy = NULL; m_weak_proxy = NULL;
} }
} }
*/
/** @name Debug methods: */
//@{
/// Get reference count. /// Get reference count.
int refCount() const int refCount() const
{ {
return m_count; 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;
}
//@}
private: private:
NVCORE_API static int s_total_ref_count;
NVCORE_API static int s_total_obj_count;
mutable int m_count; mutable int m_count;
// mutable WeakProxy * weak_proxy; mutable WeakProxy * m_weak_proxy;
}; };
} // nv namespace } // nv namespace

View File

@ -1,9 +1,11 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#pragma once
#ifndef NV_CORE_STDSTREAM_H #ifndef NV_CORE_STDSTREAM_H
#define NV_CORE_STDSTREAM_H #define NV_CORE_STDSTREAM_H
#include <nvcore/Stream.h> #include "nvcore.h"
#include "Stream.h"
#include <stdio.h> // fopen #include <stdio.h> // fopen
#include <string.h> // memcpy #include <string.h> // memcpy
@ -12,9 +14,9 @@
namespace nv namespace nv
{ {
// Portable version of fopen. // Portable version of fopen.
inline FILE * fileOpen(const char * fileName, const char * mode) inline FILE * fileOpen(const char * fileName, const char * mode)
{ {
nvCheck(fileName != NULL); nvCheck(fileName != NULL);
#if NV_CC_MSVC && _MSC_VER >= 1400 #if NV_CC_MSVC && _MSC_VER >= 1400
FILE * fp; FILE * fp;
@ -25,14 +27,14 @@ inline FILE * fileOpen(const char * fileName, const char * mode)
#else #else
return fopen(fileName, mode); return fopen(fileName, mode);
#endif #endif
} }
/// Base stdio stream. /// Base stdio stream.
class NVCORE_CLASS StdStream : public Stream class NVCORE_CLASS StdStream : public Stream
{ {
NV_FORBID_COPY(StdStream); NV_FORBID_COPY(StdStream);
public: public:
/// Ctor. /// Ctor.
StdStream( FILE * fp, bool autoclose=true ) : StdStream( FILE * fp, bool autoclose=true ) :
@ -93,19 +95,19 @@ public:
virtual bool isSeekable() const { return true; } virtual bool isSeekable() const { return true; }
//@} //@}
protected: protected:
FILE * m_fp; FILE * m_fp;
bool m_autoclose; bool m_autoclose;
}; };
/// Standard output stream. /// Standard output stream.
class NVCORE_CLASS StdOutputStream : public StdStream class NVCORE_CLASS StdOutputStream : public StdStream
{ {
NV_FORBID_COPY(StdOutputStream); NV_FORBID_COPY(StdOutputStream);
public: public:
/// Construct stream by file name. /// Construct stream by file name.
StdOutputStream( const char * name ) : StdOutputStream( const char * name ) :
@ -137,14 +139,14 @@ public:
} }
//@} //@}
}; };
/// Standard input stream. /// Standard input stream.
class NVCORE_CLASS StdInputStream : public StdStream class NVCORE_CLASS StdInputStream : public StdStream
{ {
NV_FORBID_COPY(StdInputStream); NV_FORBID_COPY(StdInputStream);
public: public:
/// Construct stream by file name. /// Construct stream by file name.
StdInputStream( const char * name ) : StdInputStream( const char * name ) :
@ -175,15 +177,15 @@ public:
return false; return false;
} }
//@} //@}
}; };
/// Memory input stream. /// Memory input stream.
class NVCORE_CLASS MemoryInputStream : public Stream class NVCORE_CLASS MemoryInputStream : public Stream
{ {
NV_FORBID_COPY(MemoryInputStream); NV_FORBID_COPY(MemoryInputStream);
public: public:
/// Ctor. /// Ctor.
MemoryInputStream( const uint8 * mem, uint size ) : MemoryInputStream( const uint8 * mem, uint size ) :
@ -257,20 +259,20 @@ public:
//@} //@}
private: private:
const uint8 * m_mem; const uint8 * m_mem;
const uint8 * m_ptr; const uint8 * m_ptr;
uint m_size; uint m_size;
}; };
/// Protected input stream. /// Protected input stream.
class NVCORE_CLASS ProtectedStream : public Stream class NVCORE_CLASS ProtectedStream : public Stream
{ {
NV_FORBID_COPY(ProtectedStream); NV_FORBID_COPY(ProtectedStream);
public: public:
/// Ctor. /// Ctor.
ProtectedStream( Stream & s ) : m_s(&s), m_autodelete(false) ProtectedStream( Stream & s ) : m_s(&s), m_autodelete(false)
@ -358,12 +360,12 @@ public:
//@} //@}
private: private:
Stream * const m_s; Stream * const m_s;
bool const m_autodelete; bool const m_autodelete;
}; };
} // nv namespace } // nv namespace

View File

@ -1,4 +1,4 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#include "StrLib.h" #include "StrLib.h"
@ -209,9 +209,9 @@ StringBuilder::StringBuilder( const StringBuilder & s ) : m_size(0), m_str(NULL)
} }
/** Copy string. */ /** 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. */ /** Delete the string. */
@ -401,11 +401,11 @@ StringBuilder & StringBuilder::reserve( uint size_hint )
/** Copy a string safely. */ /** Copy a string safely. */
StringBuilder & StringBuilder::copy( const char * s ) StringBuilder & StringBuilder::copy( const char * s, int extra_size/*=0*/ )
{ {
nvCheck( s != NULL ); nvCheck( s != NULL );
uint str_size = uint(strlen( s )) + 1; uint str_size = uint(strlen( s )) + 1;
reserve(str_size); reserve(str_size + extra_size);
strCpy( m_str, str_size, s ); strCpy( m_str, str_size, s );
return *this; return *this;
} }
@ -435,6 +435,14 @@ void StringBuilder::reset()
m_str = NULL; 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. /// Get the file name from a path.
const char * Path::fileName() const const char * Path::fileName() const
@ -467,9 +475,9 @@ void Path::translatePath()
/** /**
* Strip the file name from a path. * Strip the file name from a path.
* @warning path cannot end with '/' o '\\', can't it? * @warning path cannot end with '/' o '\\', can't it?
*/ */
void Path::stripFileName() void Path::stripFileName()
{ {
nvCheck( m_str != NULL ); nvCheck( m_str != NULL );
@ -518,7 +526,7 @@ const char * Path::fileName(const char * str)
nvCheck( str != NULL ); nvCheck( str != NULL );
int length = (int)strlen(str) - 1; int length = (int)strlen(str) - 1;
while( length >= 0 && str[length] != separator() ) { while (length >= 0 && str[length] != '\\' && str[length] != '/') {
length--; length--;
} }
@ -532,13 +540,13 @@ const char * Path::extension(const char * str)
int length, l; int length, l;
l = length = (int)strlen( str ); l = length = (int)strlen( str );
while( length > 0 && str[length] != '.' ) { while (length > 0 && str[length] != '.') {
length--; length--;
if( str[length] == separator() ) { if (str[length] != '\\' || str[length] != '/') {
return &str[l]; // no extension return &str[l]; // no extension
} }
} }
if( length == 0 ) { if (length == 0) {
return &str[l]; return &str[l];
} }
return &str[length]; return &str[length];

View File

@ -1,10 +1,12 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#pragma once
#ifndef NV_CORE_STRING_H #ifndef NV_CORE_STRING_H
#define NV_CORE_STRING_H #define NV_CORE_STRING_H
#include "nvcore.h" #include "nvcore.h"
#include "Containers.h" // swap #include "Memory.h"
#include "Utils.h" // swap, hash
#include <string.h> // strlen, strcmp, etc. #include <string.h> // strlen, strcmp, etc.
@ -25,12 +27,19 @@ namespace nv
return h; return h;
} }
template <> struct hash<const char *> { template <> struct Hash<const char *> {
uint operator()(const char * str) const { return strHash(str); } uint operator()(const char * str) const { return strHash(str); }
}; };
NVCORE_API int strCaseCmp(const char * s1, const char * s2) NV_PURE; NVCORE_API int strCaseCmp(const char * s1, const char * s2) NV_PURE;
NVCORE_API int strCmp(const char * s1, const char * s2) NV_PURE; NVCORE_API int strCmp(const char * s1, const char * s2) NV_PURE;
template <> struct Equal<const char *> {
bool operator()(const char * a, const char * b) const { return strCmp(a, b) == 0; }
};
NVCORE_API void strCpy(char * dst, int size, const char * src); 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 strCpy(char * dst, int size, const char * src, int len);
NVCORE_API void strCat(char * dst, int size, const char * src); NVCORE_API void strCat(char * dst, int size, const char * src);
@ -45,7 +54,7 @@ namespace nv
StringBuilder(); StringBuilder();
explicit StringBuilder( int size_hint ); explicit StringBuilder( int size_hint );
StringBuilder( const char * str ); StringBuilder( const char * str, int extra_size_hint = 0);
StringBuilder( const StringBuilder & ); StringBuilder( const StringBuilder & );
~StringBuilder(); ~StringBuilder();
@ -61,7 +70,7 @@ namespace nv
StringBuilder & number( uint i, int base = 10 ); StringBuilder & number( uint i, int base = 10 );
StringBuilder & reserve( uint size_hint ); StringBuilder & reserve( uint size_hint );
StringBuilder & copy( const char * str ); StringBuilder & copy( const char * str, int extra_size/*=0*/ );
StringBuilder & copy( const StringBuilder & str ); StringBuilder & copy( const StringBuilder & str );
StringBuilder & toLower(); StringBuilder & toLower();
@ -76,6 +85,8 @@ namespace nv
const char * str() const { return m_str; } const char * str() const { return m_str; }
char * str() { return m_str; } char * str() { return m_str; }
char * release();
/// Implement value semantics. /// Implement value semantics.
StringBuilder & operator=( const StringBuilder & s ) { StringBuilder & operator=( const StringBuilder & s ) {
return copy(s); return copy(s);
@ -125,7 +136,7 @@ namespace nv
public: public:
Path() : StringBuilder() {} Path() : StringBuilder() {}
explicit Path(int size_hint) : StringBuilder(size_hint) {} explicit Path(int size_hint) : StringBuilder(size_hint) {}
Path(const char * str) : StringBuilder(str) {} Path(const char * str, int extra_size_hint = 0) : StringBuilder(str, extra_size_hint) {}
Path(const Path & path) : StringBuilder(path) {} Path(const Path & path) : StringBuilder(path) {}
const char * fileName() const; const char * fileName() const;

View File

@ -1,5 +1,6 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#pragma once
#ifndef NV_CORE_STREAM_H #ifndef NV_CORE_STREAM_H
#define NV_CORE_STREAM_H #define NV_CORE_STREAM_H
@ -20,11 +21,11 @@ namespace nv
/// Get the byte order of the system. /// Get the byte order of the system.
static ByteOrder getSystemByteOrder() { static ByteOrder getSystemByteOrder() {
#if NV_LITTLE_ENDIAN #if NV_LITTLE_ENDIAN
return LittleEndian; return LittleEndian;
#else #else
return BigEndian; return BigEndian;
#endif #endif
} }
@ -74,15 +75,15 @@ namespace nv
// friends // friends
friend Stream & operator<<( Stream & s, bool & c ) { friend Stream & operator<<( Stream & s, bool & c ) {
#if NV_OS_DARWIN #if NV_OS_DARWIN
nvStaticCheck(sizeof(bool) == 4); nvStaticCheck(sizeof(bool) == 4);
uint8 b = c ? 1 : 0; uint8 b = c ? 1 : 0;
s.serialize( &b, 1 ); s.serialize( &b, 1 );
c = (b == 1); c = (b == 1);
#else #else
nvStaticCheck(sizeof(bool) == 1); nvStaticCheck(sizeof(bool) == 1);
s.serialize( &c, 1 ); s.serialize( &c, 1 );
#endif #endif
return s; return s;
} }
friend Stream & operator<<( Stream & s, char & c ) { friend Stream & operator<<( Stream & s, char & c ) {

View File

@ -1,4 +1,4 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#include "TextReader.h" #include "TextReader.h"

View File

@ -1,17 +1,19 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#ifndef NV_CORE_TEXTREADER_H #pragma once
#define NV_CORE_TEXTREADER_H #ifndef NVCORE_TEXTREADER_H
#define NVCORE_TEXTREADER_H
#include "Containers.h" #include "nvcore.h"
#include "Stream.h" #include "Stream.h"
#include "Array.h"
namespace nv namespace nv
{ {
/// Text reader. /// Text reader.
class NVCORE_CLASS TextReader { class NVCORE_CLASS TextReader {
public: public:
/// Ctor. /// Ctor.
TextReader(Stream * stream) : m_stream(stream), m_text(512) { TextReader(Stream * stream) : m_stream(stream), m_text(512) {
@ -27,11 +29,11 @@ public:
// Returns a temporary string. // Returns a temporary string.
const char * readLine(); const char * readLine();
private: private:
Stream * m_stream; Stream * m_stream;
Array<char> m_text; Array<char> m_text;
}; };
} // nv namespace } // nv namespace
#endif // NV_CORE_TEXTREADER_H #endif // NVCORE_TEXTREADER_H

View File

@ -1,4 +1,4 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#include "TextWriter.h" #include "TextWriter.h"

View File

@ -1,10 +1,12 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#ifndef NV_CORE_TEXTWRITER_H #pragma once
#define NV_CORE_TEXTWRITER_H #ifndef NVCORE_TEXTWRITER_H
#define NVCORE_TEXTWRITER_H
#include "StrLib.h" #include "nvcore.h"
#include "Stream.h" #include "Stream.h"
#include "StrLib.h"
namespace nv namespace nv
{ {
@ -57,8 +59,4 @@ namespace nv
} // nv namespace } // nv namespace
#endif // NVCORE_TEXTWRITER_H #endif // NVCORE_TEXTWRITER_H

View File

@ -1,5 +1,6 @@
// This code is in the public domain -- castano@gmail.com // This code is in the public domain -- castano@gmail.com
#pragma once
#ifndef NV_CORE_TIMER_H #ifndef NV_CORE_TIMER_H
#define NV_CORE_TIMER_H #define NV_CORE_TIMER_H

134
src/nvcore/Utils.h Normal file
View File

@ -0,0 +1,134 @@
// This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#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 <typename T>
inline void swap(T & a, T & b)
{
T temp = a;
a = b;
b = temp;
}
/// Return the maximum of the two arguments.
template <typename T>
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 <typename T>
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 <typename T>
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 <typename T>
inline const T & min(const T & a, const T & b, const T & c)
{
return min(a, min(b, c));
}
/// Clamp between two values.
template <typename T>
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 <typename Key> 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<int>
{
uint operator()(int x) const { return x; }
};
template <> struct Hash<uint>
{
uint operator()(uint x) const { return x; }
};
template <typename Key> struct Equal
{
bool operator()(const Key & k0, const Key & k1) const {
return k0 == k1;
}
};
} // nv namespace
#endif // NV_CORE_UTILS_H

View File

@ -1,5 +1,6 @@
// This code is in the public domain -- castanyo@yahoo.es // This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
#pragma once
#ifndef NV_CORE_H #ifndef NV_CORE_H
#define NV_CORE_H #define NV_CORE_H
@ -59,7 +60,6 @@
# error "Unsupported OS" # error "Unsupported OS"
#endif #endif
// CPUs: // CPUs:
// NV_CPU_X86 // NV_CPU_X86
// NV_CPU_X86_64 // NV_CPU_X86_64