Tag 2.0.6 for release.
This commit is contained in:
@ -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/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
|
168
src/nvcore/BitArray.h
Normal file
168
src/nvcore/BitArray.h
Normal file
@ -0,0 +1,168 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#ifndef NV_CORE_BITARRAY_H
|
||||
#define NV_CORE_BITARRAY_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
#include <nvcore/Containers.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
|
||||
/// Count the bits of @a x.
|
||||
inline uint bitsSet(uint8 x) {
|
||||
uint count = 0;
|
||||
for(; x != 0; x >>= 1) {
|
||||
count += (x & 1);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/// Count the bits of @a x.
|
||||
inline uint bitsSet(uint32 x, int bits) {
|
||||
uint count = 0;
|
||||
for(; x != 0 && bits != 0; x >>= 1, bits--) {
|
||||
count += (x & 1);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
/// Simple bit array.
|
||||
class BitArray
|
||||
{
|
||||
public:
|
||||
|
||||
/// Default ctor.
|
||||
BitArray() {}
|
||||
|
||||
/// Ctor with initial m_size.
|
||||
BitArray(uint sz)
|
||||
{
|
||||
resize(sz);
|
||||
}
|
||||
|
||||
/// Get array m_size.
|
||||
uint size() const { return m_size; }
|
||||
|
||||
/// Clear array m_size.
|
||||
void clear() { resize(0); }
|
||||
|
||||
/// Set array m_size.
|
||||
void resize(uint sz)
|
||||
{
|
||||
m_size = sz;
|
||||
m_bitArray.resize( (m_size + 7) >> 3 );
|
||||
}
|
||||
|
||||
/// Get bit.
|
||||
bool bitAt(uint b) const
|
||||
{
|
||||
nvDebugCheck( b < m_size );
|
||||
return (m_bitArray[b >> 3] & (1 << (b & 7))) != 0;
|
||||
}
|
||||
|
||||
/// Set a bit.
|
||||
void setBitAt(uint b)
|
||||
{
|
||||
nvDebugCheck( b < m_size );
|
||||
m_bitArray[b >> 3] |= (1 << (b & 7));
|
||||
}
|
||||
|
||||
/// Clear a bit.
|
||||
void clearBitAt( uint b )
|
||||
{
|
||||
nvDebugCheck( b < m_size );
|
||||
m_bitArray[b >> 3] &= ~(1 << (b & 7));
|
||||
}
|
||||
|
||||
/// Clear all the bits.
|
||||
void clearAll()
|
||||
{
|
||||
memset(m_bitArray.unsecureBuffer(), 0, m_bitArray.size());
|
||||
}
|
||||
|
||||
/// Set all the bits.
|
||||
void setAll()
|
||||
{
|
||||
memset(m_bitArray.unsecureBuffer(), 0xFF, m_bitArray.size());
|
||||
}
|
||||
|
||||
/// Toggle all the bits.
|
||||
void toggleAll()
|
||||
{
|
||||
const uint byte_num = m_bitArray.size();
|
||||
for(uint b = 0; b < byte_num; b++) {
|
||||
m_bitArray[b] ^= 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a byte of the bit array.
|
||||
const uint8 & byteAt(uint index) const
|
||||
{
|
||||
return m_bitArray[index];
|
||||
}
|
||||
|
||||
/// Set the given byte of the byte array.
|
||||
void setByteAt(uint index, uint8 b)
|
||||
{
|
||||
m_bitArray[index] = b;
|
||||
}
|
||||
|
||||
/// Count the number of bits set.
|
||||
uint countSetBits() const
|
||||
{
|
||||
const uint num = m_bitArray.size();
|
||||
if( num == 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint count = 0;
|
||||
for(uint i = 0; i < num - 1; i++) {
|
||||
count += bitsSet(m_bitArray[i]);
|
||||
}
|
||||
count += bitsSet(m_bitArray[num-1], m_size & 0x7);
|
||||
|
||||
//piDebugCheck(count + countClearBits() == m_size);
|
||||
return count;
|
||||
}
|
||||
|
||||
/// Count the number of bits clear.
|
||||
uint countClearBits() const {
|
||||
|
||||
const uint num = m_bitArray.size();
|
||||
if( num == 0 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint count = 0;
|
||||
for(uint i = 0; i < num - 1; i++) {
|
||||
count += bitsSet(~m_bitArray[i]);
|
||||
}
|
||||
count += bitsSet(~m_bitArray[num-1], m_size & 0x7);
|
||||
|
||||
//piDebugCheck(count + countSetBits() == m_size);
|
||||
return count;
|
||||
}
|
||||
|
||||
friend void swap(BitArray & a, BitArray & b)
|
||||
{
|
||||
swap(a.m_size, b.m_size);
|
||||
swap(a.m_bitArray, b.m_bitArray);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/// Number of bits stored.
|
||||
uint m_size;
|
||||
|
||||
/// Array of bits.
|
||||
Array<uint8> m_bitArray;
|
||||
|
||||
};
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // _PI_CORE_BITARRAY_H_
|
@ -1,25 +1,27 @@
|
||||
PROJECT(nvcore)
|
||||
ADD_SUBDIRECTORY(poshlib)
|
||||
|
||||
SET(CORE_SRCS
|
||||
nvcore.h
|
||||
Algorithms.h
|
||||
Containers.h
|
||||
Debug.h Debug.cpp
|
||||
DefsGnucDarwin.h
|
||||
DefsGnucLinux.h
|
||||
DefsGnucWin32.h
|
||||
DefsVcWin32.h
|
||||
FileSystem.h FileSystem.cpp
|
||||
Library.h Library.cpp
|
||||
Memory.h Memory.cpp
|
||||
Ptr.h
|
||||
RefCounted.h RefCounted.cpp
|
||||
StrLib.h StrLib.cpp
|
||||
BitArray.h
|
||||
Memory.h
|
||||
Memory.cpp
|
||||
Debug.h
|
||||
Debug.cpp
|
||||
Containers.h
|
||||
StrLib.h
|
||||
StrLib.cpp
|
||||
Stream.h
|
||||
StdStream.h
|
||||
TextReader.h TextReader.cpp
|
||||
TextWriter.h TextWriter.cpp
|
||||
Timer.h)
|
||||
TextReader.h
|
||||
TextReader.cpp
|
||||
TextWriter.h
|
||||
TextWriter.cpp
|
||||
Radix.h
|
||||
Radix.cpp
|
||||
Library.h
|
||||
Library.cpp)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
|
@ -19,7 +19,6 @@ Do not use memmove in insert & remove, use copy ctors instead.
|
||||
#include <nvcore/nvcore.h>
|
||||
#include <nvcore/Memory.h>
|
||||
#include <nvcore/Debug.h>
|
||||
//#include <nvcore/Stream.h>
|
||||
|
||||
#include <string.h> // memmove
|
||||
#include <new> // for placement new
|
||||
@ -71,10 +70,40 @@ namespace nv
|
||||
{
|
||||
// Templates
|
||||
|
||||
/// 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);
|
||||
}
|
||||
|
||||
/// Swap two values.
|
||||
template <typename T>
|
||||
inline void swap(T & a, T & b)
|
||||
{
|
||||
//return std::swap(a, b);
|
||||
T temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
@ -105,6 +134,16 @@ namespace nv
|
||||
uint operator()(uint x) const { return x; }
|
||||
};
|
||||
|
||||
/// 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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Return the next power of two.
|
||||
* @see http://graphics.stanford.edu/~seander/bithacks.html
|
||||
@ -115,7 +154,7 @@ namespace nv
|
||||
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.
|
||||
#if 1 // On modern CPUs this is as fast as using the bsr instruction.
|
||||
x--;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
@ -138,6 +177,15 @@ namespace nv
|
||||
return (n & (n-1)) == 0;
|
||||
}
|
||||
|
||||
/// Simple iterator interface.
|
||||
template <typename T>
|
||||
struct Iterator
|
||||
{
|
||||
virtual void advance();
|
||||
virtual bool isDone();
|
||||
virtual T current();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Replacement for std::vector that is easier to debug and provides
|
||||
@ -179,29 +227,20 @@ namespace nv
|
||||
}
|
||||
|
||||
|
||||
/// Const element access.
|
||||
/// Const and save vector 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.
|
||||
|
||||
/// Safe vector 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; }
|
||||
@ -213,7 +252,7 @@ namespace nv
|
||||
const T * buffer() const { return m_buffer; }
|
||||
|
||||
/// Get vector pointer.
|
||||
T * mutableBuffer() { return m_buffer; }
|
||||
T * unsecureBuffer() { return m_buffer; }
|
||||
|
||||
/// Is vector empty.
|
||||
bool isEmpty() const { return m_size == 0; }
|
||||
@ -294,22 +333,15 @@ namespace nv
|
||||
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);
|
||||
for (uint i = 0; i < m_size; i++) {
|
||||
if (m_buffer[i] == e) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/// Remove the element at the given index. This is an expensive operation!
|
||||
void removeAt( uint index )
|
||||
{
|
||||
@ -495,10 +527,9 @@ namespace nv
|
||||
}
|
||||
|
||||
/// Assignment operator.
|
||||
Array<T> & operator=( const Array<T> & a )
|
||||
void operator=( const Array<T> & a )
|
||||
{
|
||||
copy( a.m_buffer, a.m_size );
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -595,43 +626,18 @@ namespace nv
|
||||
template<typename T, typename U, typename hash_functor = hash<T> >
|
||||
class NVCORE_CLASS HashMap
|
||||
{
|
||||
NV_FORBID_COPY(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)
|
||||
|
@ -1,56 +0,0 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
|
||||
#include "FileSystem.h"
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
#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 <shlwapi.h> // PathFileExists
|
||||
#include <windows.h> // GetFileAttributes
|
||||
#include <direct.h> // _mkdir
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
using namespace nv;
|
||||
|
||||
|
||||
bool FileSystem::exists(const char * path)
|
||||
{
|
||||
#if NV_OS_UNIX
|
||||
return access(path, F_OK|R_OK) == 0;
|
||||
//struct stat buf;
|
||||
//return stat(path, &buf) == 0;
|
||||
#elif NV_OS_WIN32
|
||||
// PathFileExists requires linking to shlwapi.lib
|
||||
//return PathFileExists(path) != 0;
|
||||
return GetFileAttributes(path) != 0xFFFFFFFF;
|
||||
#else
|
||||
if (FILE * fp = fopen(path, "r"))
|
||||
{
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FileSystem::createDirectory(const char * path)
|
||||
{
|
||||
#if NV_OS_WIN32
|
||||
return _mkdir(path) != -1;
|
||||
#else
|
||||
return mkdir(path, 0777) != -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FileSystem::changeDirectory(const char * path)
|
||||
{
|
||||
#if NV_OS_WIN32
|
||||
return _chdir(path) != -1;
|
||||
#else
|
||||
return chdir(path) != -1;
|
||||
#endif
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
|
||||
#ifndef NV_CORE_FILESYSTEM_H
|
||||
#define NV_CORE_FILESYSTEM_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
|
||||
namespace FileSystem
|
||||
{
|
||||
|
||||
NVCORE_API bool exists(const char * path);
|
||||
NVCORE_API bool createDirectory(const char * path);
|
||||
NVCORE_API bool changeDirectory(const char * path);
|
||||
|
||||
} // FileSystem namespace
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
||||
#endif // NV_CORE_FILESYSTEM_H
|
31
src/nvcore/Prefetch.h
Normal file
31
src/nvcore/Prefetch.h
Normal file
@ -0,0 +1,31 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#ifndef NV_CORE_PREFETCH_H
|
||||
#define NV_CORE_PREFETCH_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
// nvPrefetch
|
||||
#if NV_CC_GNUC
|
||||
|
||||
#define nvPrefetch(ptr) __builtin_prefetch(ptr)
|
||||
|
||||
#elif NV_CC_MSVC
|
||||
|
||||
#if NV_CPU_X86
|
||||
__forceinline void nvPrefetch(const void * mem)
|
||||
{
|
||||
__asm mov ecx, mem
|
||||
__asm prefetcht0 [ecx];
|
||||
// __asm prefetchnta [ecx];
|
||||
}
|
||||
#endif // NV_CPU_X86
|
||||
|
||||
#else // NV_CC_MSVC
|
||||
|
||||
// do nothing in other case.
|
||||
#define nvPrefetch(ptr)
|
||||
|
||||
#endif // NV_CC_MSVC
|
||||
|
||||
#endif // NV_CORE_PREFETCH_H
|
142
src/nvcore/Ptr.h
142
src/nvcore/Ptr.h
@ -8,7 +8,6 @@
|
||||
|
||||
#include <stdio.h> // NULL
|
||||
|
||||
|
||||
namespace nv
|
||||
{
|
||||
|
||||
@ -30,11 +29,11 @@ class AutoPtr
|
||||
NV_FORBID_HEAPALLOC();
|
||||
public:
|
||||
|
||||
/// Default ctor.
|
||||
AutoPtr() : m_ptr(NULL) { }
|
||||
|
||||
/// Ctor.
|
||||
AutoPtr(T * p = NULL) : m_ptr(p) { }
|
||||
|
||||
template <class Q>
|
||||
AutoPtr(Q * p) : m_ptr(static_cast<T *>(p)) { }
|
||||
explicit AutoPtr( T * p ) : m_ptr(p) { }
|
||||
|
||||
/** Dtor. Deletes owned pointer. */
|
||||
~AutoPtr() {
|
||||
@ -51,15 +50,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <class Q>
|
||||
void operator=( Q * p ) {
|
||||
if (p != m_ptr)
|
||||
{
|
||||
delete m_ptr;
|
||||
m_ptr = static_cast<T *>(p);
|
||||
}
|
||||
}
|
||||
|
||||
/** Member access. */
|
||||
T * operator -> () const {
|
||||
nvDebugCheck(m_ptr != NULL);
|
||||
@ -106,23 +96,125 @@ private:
|
||||
T * m_ptr;
|
||||
};
|
||||
|
||||
#if 0
|
||||
/** Reference counted base class to be used with Pointer.
|
||||
*
|
||||
* The only requirement of the Pointer class is that the RefCounted class implements the
|
||||
* addRef and release methods.
|
||||
*/
|
||||
class RefCounted
|
||||
{
|
||||
NV_FORBID_COPY(RefCounted);
|
||||
public:
|
||||
|
||||
/// Ctor.
|
||||
RefCounted() : m_count(0), m_weak_proxy(NULL)
|
||||
{
|
||||
s_total_obj_count++;
|
||||
}
|
||||
|
||||
/// Virtual dtor.
|
||||
virtual ~RefCounted()
|
||||
{
|
||||
nvCheck( m_count == 0 );
|
||||
nvCheck( s_total_obj_count > 0 );
|
||||
s_total_obj_count--;
|
||||
}
|
||||
|
||||
|
||||
/// Increase reference count.
|
||||
uint addRef() const
|
||||
{
|
||||
s_total_ref_count++;
|
||||
m_count++;
|
||||
return m_count;
|
||||
}
|
||||
|
||||
|
||||
/// 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;
|
||||
}
|
||||
//@}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
NVCORE_API static int s_total_ref_count;
|
||||
NVCORE_API static int s_total_obj_count;
|
||||
|
||||
mutable int m_count;
|
||||
mutable WeakProxy * weak_proxy;
|
||||
|
||||
};
|
||||
#endif
|
||||
|
||||
/// Smart pointer template class.
|
||||
template <class BaseClass>
|
||||
class SmartPtr {
|
||||
class Pointer {
|
||||
public:
|
||||
|
||||
// BaseClass must implement addRef() and release().
|
||||
typedef SmartPtr<BaseClass> ThisType;
|
||||
typedef Pointer<BaseClass> ThisType;
|
||||
|
||||
/// Default ctor.
|
||||
SmartPtr() : m_ptr(NULL)
|
||||
Pointer() : m_ptr(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/** Other type assignment. */
|
||||
template <class OtherBase>
|
||||
SmartPtr( const SmartPtr<OtherBase> & tc )
|
||||
Pointer( const Pointer<OtherBase> & tc )
|
||||
{
|
||||
m_ptr = static_cast<BaseClass *>( tc.ptr() );
|
||||
if( m_ptr ) {
|
||||
@ -131,7 +223,7 @@ public:
|
||||
}
|
||||
|
||||
/** Copy ctor. */
|
||||
SmartPtr( const ThisType & bc )
|
||||
Pointer( const ThisType & bc )
|
||||
{
|
||||
m_ptr = bc.ptr();
|
||||
if( m_ptr ) {
|
||||
@ -139,8 +231,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/** Copy cast ctor. SmartPtr(NULL) is valid. */
|
||||
explicit SmartPtr( BaseClass * bc )
|
||||
/** Copy cast ctor. Pointer(NULL) is valid. */
|
||||
explicit Pointer( BaseClass * bc )
|
||||
{
|
||||
m_ptr = bc;
|
||||
if( m_ptr ) {
|
||||
@ -149,7 +241,7 @@ public:
|
||||
}
|
||||
|
||||
/** Dtor. */
|
||||
~SmartPtr()
|
||||
~Pointer()
|
||||
{
|
||||
set(NULL);
|
||||
}
|
||||
@ -183,7 +275,7 @@ public:
|
||||
//@{
|
||||
/** Other type assignment. */
|
||||
template <class OtherBase>
|
||||
void operator = ( const SmartPtr<OtherBase> & tc )
|
||||
void operator = ( const Pointer<OtherBase> & tc )
|
||||
{
|
||||
set( static_cast<BaseClass *>(tc.ptr()) );
|
||||
}
|
||||
@ -206,7 +298,7 @@ public:
|
||||
//@{
|
||||
/** Other type equal comparation. */
|
||||
template <class OtherBase>
|
||||
bool operator == ( const SmartPtr<OtherBase> & other ) const
|
||||
bool operator == ( const Pointer<OtherBase> & other ) const
|
||||
{
|
||||
return m_ptr == other.ptr();
|
||||
}
|
||||
@ -225,7 +317,7 @@ public:
|
||||
|
||||
/** Other type not equal comparation. */
|
||||
template <class OtherBase>
|
||||
bool operator != ( const SmartPtr<OtherBase> & other ) const
|
||||
bool operator != ( const Pointer<OtherBase> & other ) const
|
||||
{
|
||||
return m_ptr != other.ptr();
|
||||
}
|
||||
|
429
src/nvcore/Radix.cpp
Normal file
429
src/nvcore/Radix.cpp
Normal file
@ -0,0 +1,429 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains source code from the article "Radix Sort Revisited".
|
||||
* \file Radix.cpp
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Revisited Radix Sort.
|
||||
* This is my new radix routine:
|
||||
* - it uses indices and doesn't recopy the values anymore, hence wasting less ram
|
||||
* - it creates all the histograms in one run instead of four
|
||||
* - it sorts words faster than dwords and bytes faster than words
|
||||
* - it correctly sorts negative floating-point values by patching the offsets
|
||||
* - it automatically takes advantage of temporal coherence
|
||||
* - multiple keys support is a side effect of temporal coherence
|
||||
* - it may be worth recoding in asm... (mainly to use FCOMI, FCMOV, etc) [it's probably memory-bound anyway]
|
||||
*
|
||||
* History:
|
||||
* - 08.15.98: very first version
|
||||
* - 04.04.00: recoded for the radix article
|
||||
* - 12.xx.00: code lifting
|
||||
* - 09.18.01: faster CHECK_PASS_VALIDITY thanks to Mark D. Shattuck (who provided other tips, not included here)
|
||||
* - 10.11.01: added local ram support
|
||||
* - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting......
|
||||
*
|
||||
* \class RadixSort
|
||||
* \author Pierre Terdiman
|
||||
* \version 1.3
|
||||
* \date August, 15, 1998
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
To do:
|
||||
- add an offset parameter between two input values (avoid some data recopy sometimes)
|
||||
- unroll ? asm ?
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Header
|
||||
|
||||
#include <nvcore/Radix.h>
|
||||
|
||||
#include <string.h> // memset
|
||||
|
||||
//using namespace IceCore;
|
||||
|
||||
#define DELETEARRAY(a) { delete [] a; a = NULL; }
|
||||
#define CHECKALLOC(a)
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort::RadixSort() : mCurrentSize(0), mPreviousSize(0), mIndices(NULL), mIndices2(NULL), mTotalCalls(0), mNbHits(0)
|
||||
{
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
// Allocate input-independent ram
|
||||
mHistogram = new uint32[256*4];
|
||||
mOffset = new uint32[256];
|
||||
#endif
|
||||
// Initialize indices
|
||||
resetIndices();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort::~RadixSort()
|
||||
{
|
||||
// Release everything
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
DELETEARRAY(mOffset);
|
||||
DELETEARRAY(mHistogram);
|
||||
#endif
|
||||
DELETEARRAY(mIndices2);
|
||||
DELETEARRAY(mIndices);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Resizes the inner lists.
|
||||
* \param nb [in] new size (number of dwords)
|
||||
* \return true if success
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
bool RadixSort::resize(uint32 nb)
|
||||
{
|
||||
// Free previously used ram
|
||||
DELETEARRAY(mIndices2);
|
||||
DELETEARRAY(mIndices);
|
||||
|
||||
// Get some fresh one
|
||||
mIndices = new uint32[nb]; CHECKALLOC(mIndices);
|
||||
mIndices2 = new uint32[nb]; CHECKALLOC(mIndices2);
|
||||
mCurrentSize = nb;
|
||||
|
||||
// Initialize indices so that the input buffer is read in sequential order
|
||||
resetIndices();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define CHECK_RESIZE(n) \
|
||||
if(n!=mPreviousSize) \
|
||||
{ \
|
||||
if(n>mCurrentSize) resize(n); \
|
||||
else resetIndices(); \
|
||||
mPreviousSize = n; \
|
||||
}
|
||||
|
||||
#define CREATE_HISTOGRAMS(type, buffer) \
|
||||
/* Clear counters */ \
|
||||
memset(mHistogram, 0, 256*4*sizeof(uint32)); \
|
||||
\
|
||||
/* Prepare for temporal coherence */ \
|
||||
type PrevVal = (type)buffer[mIndices[0]]; \
|
||||
bool AlreadySorted = true; /* Optimism... */ \
|
||||
uint32* Indices = mIndices; \
|
||||
\
|
||||
/* Prepare to count */ \
|
||||
uint8* p = (uint8*)input; \
|
||||
uint8* pe = &p[nb*4]; \
|
||||
uint32* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \
|
||||
uint32* h1= &mHistogram[256]; /* Histogram for second pass */ \
|
||||
uint32* h2= &mHistogram[512]; /* Histogram for third pass */ \
|
||||
uint32* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \
|
||||
\
|
||||
while(p!=pe) \
|
||||
{ \
|
||||
/* Read input buffer in previous sorted order */ \
|
||||
type Val = (type)buffer[*Indices++]; \
|
||||
/* Check whether already sorted or not */ \
|
||||
if(Val<PrevVal) { AlreadySorted = false; break; } /* Early out */ \
|
||||
/* Update for next iteration */ \
|
||||
PrevVal = Val; \
|
||||
\
|
||||
/* Create histograms */ \
|
||||
h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
|
||||
} \
|
||||
\
|
||||
/* If all input values are already sorted, we just have to return and leave the */ \
|
||||
/* previous list unchanged. That way the routine may take advantage of temporal */ \
|
||||
/* coherence, for example when used to sort transparent faces. */ \
|
||||
if(AlreadySorted) { mNbHits++; return *this; } \
|
||||
\
|
||||
/* Else there has been an early out and we must finish computing the histograms */ \
|
||||
while(p!=pe) \
|
||||
{ \
|
||||
/* Create histograms without the previous overhead */ \
|
||||
h0[*p++]++; h1[*p++]++; h2[*p++]++; h3[*p++]++; \
|
||||
}
|
||||
|
||||
#define CHECK_PASS_VALIDITY(pass) \
|
||||
/* Shortcut to current counters */ \
|
||||
uint32* CurCount = &mHistogram[pass<<8]; \
|
||||
\
|
||||
/* Reset flag. The sorting pass is supposed to be performed. (default) */ \
|
||||
bool PerformPass = true; \
|
||||
\
|
||||
/* Check pass validity */ \
|
||||
\
|
||||
/* If all values have the same byte, sorting is useless. */ \
|
||||
/* It may happen when sorting bytes or words instead of dwords. */ \
|
||||
/* This routine actually sorts words faster than dwords, and bytes */ \
|
||||
/* faster than words. Standard running time (O(4*n))is reduced to O(2*n) */ \
|
||||
/* for words and O(n) for bytes. Running time for floats depends on actual values... */ \
|
||||
\
|
||||
/* Get first byte */ \
|
||||
uint8 UniqueVal = *(((uint8*)input)+pass); \
|
||||
\
|
||||
/* Check that byte's counter */ \
|
||||
if(CurCount[UniqueVal]==nb) PerformPass=false;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Main sort routine.
|
||||
* This one is for integer values. After the call, mIndices contains a list of indices in sorted order, i.e. in the order you may process your data.
|
||||
* \param input [in] a list of integer values to sort
|
||||
* \param nb [in] number of values to sort
|
||||
* \param signedvalues [in] true to handle negative values, false if you know your input buffer only contains positive values
|
||||
* \return Self-Reference
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort& RadixSort::sort(const uint32* input, uint32 nb, bool signedvalues)
|
||||
{
|
||||
uint32 i, j;
|
||||
|
||||
// Checkings
|
||||
if(!input || !nb) return *this;
|
||||
|
||||
// Stats
|
||||
mTotalCalls++;
|
||||
|
||||
// Resize lists if needed
|
||||
CHECK_RESIZE(nb);
|
||||
|
||||
#ifdef RADIX_LOCAL_RAM
|
||||
// Allocate histograms & offsets on the stack
|
||||
uint32 mHistogram[256*4];
|
||||
uint32 mOffset[256];
|
||||
#endif
|
||||
|
||||
// Create histograms (counters). Counters for all passes are created in one run.
|
||||
// Pros: read input buffer once instead of four times
|
||||
// Cons: mHistogram is 4Kb instead of 1Kb
|
||||
// We must take care of signed/unsigned values for temporal coherence.... I just
|
||||
// have 2 code paths even if just a single opcode changes. Self-modifying code, someone?
|
||||
if(!signedvalues) { CREATE_HISTOGRAMS(uint32, input); }
|
||||
else { CREATE_HISTOGRAMS(int32, input); }
|
||||
|
||||
// Compute #negative values involved if needed
|
||||
uint32 NbNegativeValues = 0;
|
||||
if(signedvalues)
|
||||
{
|
||||
// An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
|
||||
// last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
|
||||
// responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
|
||||
uint32* h3= &mHistogram[768];
|
||||
for( i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
|
||||
}
|
||||
|
||||
// Radix sort, j is the pass number (0=LSB, 3=MSB)
|
||||
for( j=0;j<4;j++)
|
||||
{
|
||||
CHECK_PASS_VALIDITY(j);
|
||||
|
||||
// Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is
|
||||
// not a problem, numbers are correctly sorted anyway.
|
||||
if(PerformPass)
|
||||
{
|
||||
// Should we care about negative values?
|
||||
if(j!=3 || !signedvalues)
|
||||
{
|
||||
// Here we deal with positive values only
|
||||
|
||||
// Create offsets
|
||||
mOffset[0] = 0;
|
||||
for(i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place.
|
||||
|
||||
// Create biased offsets, in order for negative numbers to be sorted as well
|
||||
mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
|
||||
for(i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
|
||||
// Fixing the wrong place for negative values
|
||||
mOffset[128] = 0;
|
||||
for(i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
}
|
||||
|
||||
// Perform Radix Sort
|
||||
uint8* InputBytes = (uint8*)input;
|
||||
uint32* Indices = mIndices;
|
||||
uint32* IndicesEnd = &mIndices[nb];
|
||||
InputBytes += j;
|
||||
while(Indices!=IndicesEnd)
|
||||
{
|
||||
uint32 id = *Indices++;
|
||||
mIndices2[mOffset[InputBytes[id<<2]]++] = id;
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mIndices after the swap.
|
||||
uint32* Tmp = mIndices; mIndices = mIndices2; mIndices2 = Tmp;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Main sort routine.
|
||||
* This one is for floating-point values. After the call, mIndices contains a list of indices in sorted order, i.e. in the order you may process your data.
|
||||
* \param input [in] a list of floating-point values to sort
|
||||
* \param nb [in] number of values to sort
|
||||
* \return Self-Reference
|
||||
* \warning only sorts IEEE floating-point values
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
RadixSort& RadixSort::sort(const float* input2, uint32 nb)
|
||||
{
|
||||
uint32 i, j;
|
||||
|
||||
// Checkings
|
||||
if(!input2 || !nb) return *this;
|
||||
|
||||
// Stats
|
||||
mTotalCalls++;
|
||||
|
||||
uint32* input = (uint32*)input2;
|
||||
|
||||
// Resize lists if needed
|
||||
CHECK_RESIZE(nb);
|
||||
|
||||
#ifdef RADIX_LOCAL_RAM
|
||||
// Allocate histograms & offsets on the stack
|
||||
uint32 mHistogram[256*4];
|
||||
uint32 mOffset[256];
|
||||
#endif
|
||||
|
||||
// Create histograms (counters). Counters for all passes are created in one run.
|
||||
// Pros: read input buffer once instead of four times
|
||||
// Cons: mHistogram is 4Kb instead of 1Kb
|
||||
// Floating-point values are always supposed to be signed values, so there's only one code path there.
|
||||
// Please note the floating point comparison needed for temporal coherence! Although the resulting asm code
|
||||
// is dreadful, this is surprisingly not such a performance hit - well, I suppose that's a big one on first
|
||||
// generation Pentiums....We can't make comparison on integer representations because, as Chris said, it just
|
||||
// wouldn't work with mixed positive/negative values....
|
||||
{ CREATE_HISTOGRAMS(float, input2); }
|
||||
|
||||
// Compute #negative values involved if needed
|
||||
uint32 NbNegativeValues = 0;
|
||||
// An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128
|
||||
// last values of the last histogram. Last histogram because that's the one for the Most Significant Byte,
|
||||
// responsible for the sign. 128 last values because the 128 first ones are related to positive numbers.
|
||||
uint32* h3= &mHistogram[768];
|
||||
for( i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part
|
||||
|
||||
// Radix sort, j is the pass number (0=LSB, 3=MSB)
|
||||
for( j=0;j<4;j++)
|
||||
{
|
||||
// Should we care about negative values?
|
||||
if(j!=3)
|
||||
{
|
||||
// Here we deal with positive values only
|
||||
CHECK_PASS_VALIDITY(j);
|
||||
|
||||
if(PerformPass)
|
||||
{
|
||||
// Create offsets
|
||||
mOffset[0] = 0;
|
||||
for( i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1];
|
||||
|
||||
// Perform Radix Sort
|
||||
uint8* InputBytes = (uint8*)input;
|
||||
uint32* Indices = mIndices;
|
||||
uint32* IndicesEnd = &mIndices[nb];
|
||||
InputBytes += j;
|
||||
while(Indices!=IndicesEnd)
|
||||
{
|
||||
uint32 id = *Indices++;
|
||||
mIndices2[mOffset[InputBytes[id<<2]]++] = id;
|
||||
}
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mIndices after the swap.
|
||||
uint32* Tmp = mIndices; mIndices = mIndices2; mIndices2 = Tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a special case to correctly handle negative values
|
||||
CHECK_PASS_VALIDITY(j);
|
||||
|
||||
if(PerformPass)
|
||||
{
|
||||
// Create biased offsets, in order for negative numbers to be sorted as well
|
||||
mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones
|
||||
for(i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers
|
||||
|
||||
// We must reverse the sorting order for negative numbers!
|
||||
mOffset[255] = 0;
|
||||
for(i=0;i<127;i++) mOffset[254-i] = mOffset[255-i] + CurCount[255-i]; // Fixing the wrong order for negative values
|
||||
for(i=128;i<256;i++) mOffset[i] += CurCount[i]; // Fixing the wrong place for negative values
|
||||
|
||||
// Perform Radix Sort
|
||||
for(i=0;i<nb;i++)
|
||||
{
|
||||
uint32 Radix = input[mIndices[i]]>>24; // Radix byte, same as above. AND is useless here (uint32).
|
||||
// ### cmp to be killed. Not good. Later.
|
||||
if(Radix<128) mIndices2[mOffset[Radix]++] = mIndices[i]; // Number is positive, same as above
|
||||
else mIndices2[--mOffset[Radix]] = mIndices[i]; // Number is negative, flip the sorting order
|
||||
}
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mIndices after the swap.
|
||||
uint32* Tmp = mIndices; mIndices = mIndices2; mIndices2 = Tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The pass is useless, yet we still have to reverse the order of current list if all values are negative.
|
||||
if(UniqueVal>=128)
|
||||
{
|
||||
for(i=0;i<nb;i++) mIndices2[i] = mIndices[nb-i-1];
|
||||
|
||||
// Swap pointers for next pass. Valid indices - the most recent ones - are in mIndices after the swap.
|
||||
uint32* Tmp = mIndices; mIndices = mIndices2; mIndices2 = Tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Resets the inner indices. After the call, mIndices is reset.
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void RadixSort::resetIndices()
|
||||
{
|
||||
for(uint32 i=0;i<mCurrentSize;i++) mIndices[i] = i;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Gets the ram used.
|
||||
* \return memory used in bytes
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
uint32 RadixSort::usedRam() const
|
||||
{
|
||||
uint32 UsedRam = sizeof(RadixSort);
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
UsedRam += 256*4*sizeof(uint32); // Histograms
|
||||
UsedRam += 256*sizeof(uint32); // Offsets
|
||||
#endif
|
||||
UsedRam += 2*mCurrentSize*sizeof(uint32); // 2 lists of indices
|
||||
return UsedRam;
|
||||
}
|
69
src/nvcore/Radix.h
Normal file
69
src/nvcore/Radix.h
Normal file
@ -0,0 +1,69 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/**
|
||||
* Contains source code from the article "Radix Sort Revisited".
|
||||
* \file Radix.h
|
||||
* \author Pierre Terdiman
|
||||
* \date April, 4, 2000
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Include Guard
|
||||
#ifndef NV_CORE_RADIXSORT_H
|
||||
#define NV_CORE_RADIXSORT_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
|
||||
#define RADIX_LOCAL_RAM
|
||||
|
||||
|
||||
class NVCORE_API RadixSort {
|
||||
NV_FORBID_COPY(RadixSort);
|
||||
public:
|
||||
// Constructor/Destructor
|
||||
RadixSort();
|
||||
~RadixSort();
|
||||
|
||||
// Sorting methods
|
||||
RadixSort & sort(const uint32* input, uint32 nb, bool signedvalues=true);
|
||||
RadixSort & sort(const float* input, uint32 nb);
|
||||
|
||||
//! Access to results. mIndices is a list of indices in sorted order, i.e. in the order you may further process your data
|
||||
inline uint32 * indices() const { return mIndices; }
|
||||
|
||||
//! mIndices2 gets trashed on calling the sort routine, but otherwise you can recycle it the way you want.
|
||||
inline uint32 * recyclable() const { return mIndices2; }
|
||||
|
||||
// Stats
|
||||
uint32 usedRam() const;
|
||||
|
||||
//! Returns the total number of calls to the radix sorter.
|
||||
inline uint32 totalCalls() const { return mTotalCalls; }
|
||||
|
||||
//! Returns the number of premature exits due to temporal coherence.
|
||||
inline uint32 hits() const { return mNbHits; }
|
||||
|
||||
|
||||
private:
|
||||
#ifndef RADIX_LOCAL_RAM
|
||||
uint32* mHistogram; //!< Counters for each byte
|
||||
uint32* mOffset; //!< Offsets (nearly a cumulative distribution function)
|
||||
#endif
|
||||
uint32 mCurrentSize; //!< Current size of the indices list
|
||||
uint32 mPreviousSize; //!< Size involved in previous call
|
||||
uint32* mIndices; //!< Two lists, swapped each pass
|
||||
uint32* mIndices2;
|
||||
|
||||
// Stats
|
||||
uint32 mTotalCalls;
|
||||
uint32 mNbHits;
|
||||
|
||||
// Internal methods
|
||||
bool resize(uint32 nb);
|
||||
void resetIndices();
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // NV_CORE_RADIXSORT_H
|
@ -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;
|
||||
|
@ -1,114 +0,0 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#ifndef NV_CORE_REFCOUNTED_H
|
||||
#define NV_CORE_REFCOUNTED_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
#include <nvcore/Debug.h>
|
||||
|
||||
|
||||
namespace nv
|
||||
{
|
||||
|
||||
/// 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)*/
|
||||
{
|
||||
s_total_obj_count++;
|
||||
}
|
||||
|
||||
/// Virtual dtor.
|
||||
virtual ~RefCounted()
|
||||
{
|
||||
nvCheck( m_count == 0 );
|
||||
nvCheck( s_total_obj_count > 0 );
|
||||
s_total_obj_count--;
|
||||
}
|
||||
|
||||
|
||||
/// Increase reference count.
|
||||
uint addRef() const
|
||||
{
|
||||
s_total_ref_count++;
|
||||
m_count++;
|
||||
return m_count;
|
||||
}
|
||||
|
||||
|
||||
/// 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;
|
||||
}
|
||||
//@}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
NVCORE_API static int s_total_ref_count;
|
||||
NVCORE_API static int s_total_obj_count;
|
||||
|
||||
mutable int m_count;
|
||||
// mutable WeakProxy * weak_proxy;
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
||||
#endif // NV_CORE_REFCOUNTED_H
|
@ -1,7 +1,5 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
|
||||
#ifndef NV_CORE_STDSTREAM_H
|
||||
#define NV_CORE_STDSTREAM_H
|
||||
#ifndef NV_STDSTREAM_H
|
||||
#define NV_STDSTREAM_H
|
||||
|
||||
#include <nvcore/Stream.h>
|
||||
|
||||
@ -368,4 +366,4 @@ private:
|
||||
} // nv namespace
|
||||
|
||||
|
||||
#endif // NV_CORE_STDSTREAM_H
|
||||
#endif // NV_STDSTREAM_H
|
||||
|
@ -1,7 +1,7 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#ifndef NV_CORE_STREAM_H
|
||||
#define NV_CORE_STREAM_H
|
||||
#ifndef NVCORE_STREAM_H
|
||||
#define NVCORE_STREAM_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
#include <nvcore/Debug.h>
|
||||
@ -9,152 +9,152 @@
|
||||
namespace nv
|
||||
{
|
||||
|
||||
/// Base stream class.
|
||||
class NVCORE_CLASS Stream {
|
||||
public:
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
/// Ctor.
|
||||
Stream() : m_byteOrder(LittleEndian) { }
|
||||
|
||||
/// Virtual destructor.
|
||||
virtual ~Stream() {}
|
||||
|
||||
/// Set byte order.
|
||||
void setByteOrder(ByteOrder bo) { m_byteOrder = bo; }
|
||||
|
||||
/// Get byte order.
|
||||
ByteOrder byteOrder() const { return m_byteOrder; }
|
||||
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
ByteOrder m_byteOrder;
|
||||
/// Base stream class.
|
||||
class NVCORE_CLASS Stream {
|
||||
public:
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
/// Ctor.
|
||||
Stream() : m_byteOrder(LittleEndian) { }
|
||||
|
||||
/// Virtual destructor.
|
||||
virtual ~Stream() {}
|
||||
|
||||
/// Set byte order.
|
||||
void setByteOrder(ByteOrder bo) { m_byteOrder = bo; }
|
||||
|
||||
/// Get byte order.
|
||||
ByteOrder byteOrder() const { return m_byteOrder; }
|
||||
|
||||
|
||||
/// 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;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
ByteOrder m_byteOrder;
|
||||
|
||||
};
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // NV_CORE_STREAM_H
|
||||
#endif // NV_STREAM_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#include "TextReader.h"
|
||||
#include <nvcore/TextReader.h>
|
||||
|
||||
using namespace nv;
|
||||
|
||||
@ -48,7 +48,7 @@ const char * TextReader::readToEnd()
|
||||
m_text.reserve(size + 1);
|
||||
m_text.resize(size);
|
||||
|
||||
m_stream->serialize(m_text.mutableBuffer(), size);
|
||||
m_stream->serialize(m_text.unsecureBuffer(), size);
|
||||
m_text.pushBack('\0');
|
||||
|
||||
return m_text.buffer();
|
||||
|
@ -1,10 +1,11 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#ifndef NV_CORE_TEXTREADER_H
|
||||
#define NV_CORE_TEXTREADER_H
|
||||
#ifndef NVCORE_TEXTREADER_H
|
||||
#define NVCORE_TEXTREADER_H
|
||||
|
||||
#include <nvcore/Containers.h>
|
||||
#include <nvcore/nvcore.h>
|
||||
#include <nvcore/Stream.h>
|
||||
#include <nvcore/Containers.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
@ -34,4 +35,4 @@ private:
|
||||
|
||||
} // nv namespace
|
||||
|
||||
#endif // NV_CORE_TEXTREADER_H
|
||||
#endif // NVCORE_TEXTREADER_H
|
||||
|
@ -1,6 +1,6 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#include "TextWriter.h"
|
||||
#include <nvcore/TextWriter.h>
|
||||
|
||||
using namespace nv;
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#ifndef NV_CORE_TEXTWRITER_H
|
||||
#define NV_CORE_TEXTWRITER_H
|
||||
#ifndef NVCORE_TEXTWRITER_H
|
||||
#define NVCORE_TEXTWRITER_H
|
||||
|
||||
#include <nvcore/StrLib.h>
|
||||
#include <nvcore/nvcore.h>
|
||||
#include <nvcore/Stream.h>
|
||||
#include <nvcore/StrLib.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
|
@ -1,22 +0,0 @@
|
||||
// This code is in the public domain -- castano@gmail.com
|
||||
|
||||
#ifndef NV_CORE_TIMER_H
|
||||
#define NV_CORE_TIMER_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
|
||||
#include <time.h> //clock
|
||||
|
||||
class NVCORE_CLASS Timer
|
||||
{
|
||||
public:
|
||||
Timer() {}
|
||||
|
||||
void start() { m_start = clock(); }
|
||||
int elapsed() const { return (1000 * (clock() - m_start)) / CLOCKS_PER_SEC; }
|
||||
|
||||
private:
|
||||
clock_t m_start;
|
||||
};
|
||||
|
||||
#endif // NV_CORE_TIMER_H
|
229
src/nvcore/Tokenizer.cpp
Normal file
229
src/nvcore/Tokenizer.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#include <nvcore/Tokenizer.h>
|
||||
#include <nvcore/StrLib.h>
|
||||
|
||||
#include <stdio.h> // vsscanf
|
||||
#include <stdarg.h> // va_list
|
||||
#include <stdlib.h> // atof, atoi
|
||||
|
||||
#if NV_CC_MSVC
|
||||
#if 0 // This doesn't work on MSVC for x64
|
||||
/* vsscanf for Win32
|
||||
* Written 5/2003 by <mgix@mgix.com>
|
||||
* This code is in the Public Domain
|
||||
*/
|
||||
|
||||
#include <malloc.h> // alloca
|
||||
//#include <string.h>
|
||||
|
||||
static int vsscanf(const char * buffer, const char * format, va_list argPtr)
|
||||
{
|
||||
// Get an upper bound for the # of args
|
||||
size_t count = 0;
|
||||
const char *p = format;
|
||||
while(1) {
|
||||
char c = *(p++);
|
||||
if(c==0) break;
|
||||
if(c=='%' && (p[0]!='*' && p[0]!='%')) ++count;
|
||||
}
|
||||
|
||||
// Make a local stack
|
||||
size_t stackSize = (2+count)*sizeof(void*);
|
||||
void **newStack = (void**)alloca(stackSize);
|
||||
|
||||
// Fill local stack the way sscanf likes it
|
||||
newStack[0] = (void*)buffer;
|
||||
newStack[1] = (void*)format;
|
||||
memcpy(newStack+2, argPtr, count*sizeof(void*));
|
||||
|
||||
// @@ Use: CALL DWORD PTR [sscanf]
|
||||
|
||||
// Warp into system sscanf with new stack
|
||||
int result;
|
||||
void *savedESP;
|
||||
__asm
|
||||
{
|
||||
mov savedESP, esp
|
||||
mov esp, newStack
|
||||
#if _MSC_VER >= 1400
|
||||
call DWORD PTR [sscanf_s]
|
||||
#else
|
||||
call DWORD PTR [sscanf]
|
||||
#endif
|
||||
mov esp, savedESP
|
||||
mov result, eax
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace nv;
|
||||
|
||||
Token::Token() :
|
||||
m_str(""), m_len(0)
|
||||
{
|
||||
}
|
||||
|
||||
Token::Token(const Token & token) :
|
||||
m_str(token.m_str), m_len(token.m_len)
|
||||
{
|
||||
}
|
||||
|
||||
Token::Token(const char * str, int len) :
|
||||
m_str(str), m_len(len)
|
||||
{
|
||||
}
|
||||
|
||||
bool Token::operator==(const char * str) const
|
||||
{
|
||||
return strncmp(m_str, str, m_len) == 0;
|
||||
}
|
||||
bool Token::operator!=(const char * str) const
|
||||
{
|
||||
return strncmp(m_str, str, m_len) != 0;
|
||||
}
|
||||
|
||||
bool Token::isNull()
|
||||
{
|
||||
return m_len != 0;
|
||||
}
|
||||
|
||||
float Token::toFloat() const
|
||||
{
|
||||
return float(atof(m_str));
|
||||
}
|
||||
|
||||
int Token::toInt() const
|
||||
{
|
||||
return atoi(m_str);
|
||||
}
|
||||
|
||||
uint Token::toUnsignedInt() const
|
||||
{
|
||||
// @@ TBD
|
||||
return uint(atoi(m_str));
|
||||
}
|
||||
|
||||
String Token::toString() const
|
||||
{
|
||||
return String(m_str, m_len);
|
||||
}
|
||||
|
||||
bool Token::parse(const char * format, int count, ...) const
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, count);
|
||||
|
||||
int readCount = vsscanf(m_str, format, arg);
|
||||
|
||||
va_end(arg);
|
||||
|
||||
return readCount == count;
|
||||
}
|
||||
|
||||
|
||||
Tokenizer::Tokenizer(Stream * stream) :
|
||||
m_reader(stream), m_lineNumber(0), m_columnNumber(0), m_delimiters("{}()="), m_spaces(" \t")
|
||||
{
|
||||
}
|
||||
|
||||
bool Tokenizer::nextLine(bool skipEmptyLines /*= true*/)
|
||||
{
|
||||
do {
|
||||
if (!readLine()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (!readToken() && skipEmptyLines);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tokenizer::nextToken(bool skipEndOfLine /*= false*/)
|
||||
{
|
||||
if (!readToken()) {
|
||||
if (!skipEndOfLine) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return nextLine(true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tokenizer::readToken()
|
||||
{
|
||||
skipSpaces();
|
||||
|
||||
const char * begin = m_line + m_columnNumber;
|
||||
|
||||
if (*begin == '\0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
char c = readChar();
|
||||
if (isDelimiter(c)) {
|
||||
m_token = Token(begin, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
// @@ Add support for quoted tokens "", ''
|
||||
|
||||
int len = 0;
|
||||
while (!isDelimiter(c) && !isSpace(c) && c != '\0') {
|
||||
c = readChar();
|
||||
len++;
|
||||
}
|
||||
m_columnNumber--;
|
||||
|
||||
m_token = Token(begin, len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
char Tokenizer::readChar()
|
||||
{
|
||||
return m_line[m_columnNumber++];
|
||||
}
|
||||
|
||||
bool Tokenizer::readLine()
|
||||
{
|
||||
m_lineNumber++;
|
||||
m_columnNumber = 0;
|
||||
m_line = m_reader.readLine();
|
||||
return m_line != NULL;
|
||||
}
|
||||
|
||||
void Tokenizer::skipSpaces()
|
||||
{
|
||||
while (isSpace(readChar())) {}
|
||||
m_columnNumber--;
|
||||
}
|
||||
|
||||
bool Tokenizer::isSpace(char c)
|
||||
{
|
||||
uint i = 0;
|
||||
while (m_spaces[i] != '\0') {
|
||||
if (c == m_spaces[i]) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Tokenizer::isDelimiter(char c)
|
||||
{
|
||||
uint i = 0;
|
||||
while (m_delimiters[i] != '\0') {
|
||||
if (c == m_delimiters[i]) {
|
||||
return true;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
99
src/nvcore/Tokenizer.h
Normal file
99
src/nvcore/Tokenizer.h
Normal file
@ -0,0 +1,99 @@
|
||||
// This code is in the public domain -- castanyo@yahoo.es
|
||||
|
||||
#ifndef NV_CORE_TOKENIZER_H
|
||||
#define NV_CORE_TOKENIZER_H
|
||||
|
||||
#include <nvcore/nvcore.h>
|
||||
#include <nvcore/Stream.h>
|
||||
#include <nvcore/TextReader.h>
|
||||
#include <nvcore/StrLib.h>
|
||||
|
||||
namespace nv
|
||||
{
|
||||
/// A token produced by the Tokenizer.
|
||||
class NVCORE_CLASS Token
|
||||
{
|
||||
public:
|
||||
Token();
|
||||
Token(const Token & token);
|
||||
Token(const char * str, int len);
|
||||
|
||||
bool operator==(const char * str) const;
|
||||
bool operator!=(const char * str) const;
|
||||
|
||||
bool isNull();
|
||||
|
||||
float toFloat() const;
|
||||
int toInt() const;
|
||||
uint toUnsignedInt() const;
|
||||
String toString() const;
|
||||
|
||||
bool parse(const char * format, int count, ...) const __attribute__((format (scanf, 2, 4)));
|
||||
|
||||
private:
|
||||
const char * m_str;
|
||||
int m_len;
|
||||
};
|
||||
|
||||
/// Exception thrown by the tokenizer.
|
||||
class TokenizerException
|
||||
{
|
||||
public:
|
||||
TokenizerException(int line, int column) : m_line(line), m_column(column) {}
|
||||
|
||||
int line() const { return m_line; }
|
||||
int column() const { return m_column; }
|
||||
|
||||
private:
|
||||
int m_line;
|
||||
int m_column;
|
||||
};
|
||||
|
||||
// @@ Use enums instead of bools for clarity!
|
||||
//enum SkipEmptyLines { skipEmptyLines, noSkipEmptyLines };
|
||||
//enum SkipEndOfLine { skipEndOfLine, noSkipEndOfLine };
|
||||
|
||||
/// A simple stream tokenizer.
|
||||
class NVCORE_CLASS Tokenizer
|
||||
{
|
||||
public:
|
||||
Tokenizer(Stream * stream);
|
||||
|
||||
bool nextLine(bool skipEmptyLines = true);
|
||||
bool nextToken(bool skipEndOfLine = false);
|
||||
|
||||
const Token & token() const { return m_token; }
|
||||
|
||||
int lineNumber() const { return m_lineNumber; }
|
||||
int columnNumber() const { return m_columnNumber; }
|
||||
|
||||
void setDelimiters(const char * str) { m_delimiters = str; }
|
||||
const char * delimiters() const { return m_delimiters; }
|
||||
|
||||
void setSpaces(const char * str) { m_spaces = str; }
|
||||
const char * spaces() const { return m_spaces; }
|
||||
|
||||
private:
|
||||
char readChar();
|
||||
bool readLine();
|
||||
bool readToken();
|
||||
void skipSpaces();
|
||||
bool isSpace(char c);
|
||||
bool isDelimiter(char c);
|
||||
|
||||
private:
|
||||
TextReader m_reader;
|
||||
const char * m_line;
|
||||
Token m_token;
|
||||
|
||||
int m_lineNumber;
|
||||
int m_columnNumber;
|
||||
|
||||
const char * m_delimiters;
|
||||
const char * m_spaces;
|
||||
};
|
||||
|
||||
} // nv namespace
|
||||
|
||||
|
||||
#endif // NV_CORE_TOKENIZER_H
|
@ -22,7 +22,7 @@
|
||||
|
||||
|
||||
// Platform definitions
|
||||
#include <posh.h>
|
||||
#include "poshlib/posh.h"
|
||||
|
||||
// OS:
|
||||
// NV_OS_WIN32
|
||||
@ -126,9 +126,6 @@
|
||||
#define NV_DO_STRING_JOIN2(arg1, arg2) arg1 ## arg2
|
||||
#define NV_STRING_JOIN3(arg1, arg2, arg3) NV_DO_STRING_JOIN3(arg1, arg2, arg3)
|
||||
#define NV_DO_STRING_JOIN3(arg1, arg2, arg3) arg1 ## arg2 ## arg3
|
||||
#define NV_STRING2(x) #x
|
||||
#define NV_STRING(x) NV_STRING2(x)
|
||||
#define NV_FILE_LINE __FILE__ "(" NV_STRING(__LINE__) ") : "
|
||||
|
||||
// Startup initialization macro.
|
||||
#define NV_AT_STARTUP(some_code) \
|
||||
|
7
src/nvcore/poshlib/CMakeLists.txt
Normal file
7
src/nvcore/poshlib/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
SET(POSHLIB_SRCS
|
||||
posh.c
|
||||
posh.h)
|
||||
|
||||
ADD_LIBRARY(posh STATIC ${POSHLIB_SRCS})
|
||||
|
1006
src/nvcore/poshlib/posh.c
Normal file
1006
src/nvcore/poshlib/posh.c
Normal file
File diff suppressed because it is too large
Load Diff
1007
src/nvcore/poshlib/posh.h
Normal file
1007
src/nvcore/poshlib/posh.h
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user