Merge private branch.
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.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
525
src/nvcore/Array.h
Normal 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
|
@ -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
@ -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"
|
||||||
@ -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,8 +332,6 @@ 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");
|
||||||
@ -393,7 +389,7 @@ namespace
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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 );
|
||||||
@ -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;
|
||||||
@ -437,16 +433,16 @@ int nvAbort(const char * exp, const char * file, int line, const char * func)
|
|||||||
#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);
|
||||||
|
@ -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); \
|
||||||
@ -32,10 +31,10 @@
|
|||||||
|
|
||||||
# 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");
|
||||||
@ -47,6 +46,12 @@
|
|||||||
// 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)) { \
|
||||||
@ -56,6 +61,18 @@
|
|||||||
} \
|
} \
|
||||||
} 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();
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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
563
src/nvcore/HashMap.h
Normal 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
|
@ -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
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
136
src/nvcore/Ptr.h
136
src/nvcore/Ptr.h
@ -1,4 +1,4 @@
|
|||||||
// This code is in the public domain -- castanyo@yahoo.es
|
// This code is in the public domain -- Ignacio Casta<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,11 +6,11 @@
|
|||||||
#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.
|
||||||
*
|
*
|
||||||
@ -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,44 +60,44 @@ 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);
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Other type assignment. */
|
/// Other type assignment.
|
||||||
template <class OtherBase>
|
template <class OtherBase>
|
||||||
SmartPtr( const SmartPtr<OtherBase> & tc )
|
SmartPtr( const SmartPtr<OtherBase> & tc )
|
||||||
{
|
{
|
||||||
@ -130,7 +130,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy ctor. */
|
/// Copy ctor.
|
||||||
SmartPtr( const ThisType & bc )
|
SmartPtr( const ThisType & bc )
|
||||||
{
|
{
|
||||||
m_ptr = bc.ptr();
|
m_ptr = bc.ptr();
|
||||||
@ -139,7 +139,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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;
|
||||||
@ -148,118 +148,110 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 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();
|
||||||
}
|
}
|
||||||
//@}
|
|
||||||
|
bool isValid() const {
|
||||||
|
return isValidPtr(m_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Set this pointer. */
|
// Set this pointer.
|
||||||
void set( BaseClass * p )
|
void set( BaseClass * p )
|
||||||
{
|
{
|
||||||
if( m_ptr != p ) {
|
|
||||||
if( m_ptr ) m_ptr->release();
|
|
||||||
if (p) p->addRef();
|
if (p) p->addRef();
|
||||||
|
if (m_ptr) m_ptr->release();
|
||||||
m_ptr = p;
|
m_ptr = p;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -267,6 +259,64 @@ private:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
|
||||||
#endif // NV_CORE_PTR_H
|
#endif // NV_CORE_PTR_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,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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
@ -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--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -534,7 +542,7 @@ const char * Path::extension(const char * str)
|
|||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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_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
|
||||||
{
|
{
|
||||||
@ -34,4 +36,4 @@ private:
|
|||||||
|
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
#endif // NV_CORE_TEXTREADER_H
|
#endif // NVCORE_TEXTREADER_H
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
134
src/nvcore/Utils.h
Normal 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
|
@ -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
|
||||||
|
Reference in New Issue
Block a user