Merge changes from the witness.
This commit is contained in:
parent
343d6e1450
commit
327f344bd0
|
@ -14,19 +14,15 @@ container. This is forbidden to prevent an extra copy.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "nvcore.h"
|
|
||||||
#include "Memory.h"
|
#include "Memory.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "Stream.h"
|
|
||||||
#include "Utils.h" // swap
|
|
||||||
#include "ForEach.h" // PseudoIndex
|
#include "ForEach.h" // PseudoIndex
|
||||||
|
|
||||||
#include <string.h> // memmove
|
|
||||||
#include <new> // for placement new
|
|
||||||
|
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
|
class Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replacement for std::vector that is easier to debug and provides
|
* Replacement for std::vector that is easier to debug and provides
|
||||||
* some nice foreach enumerators.
|
* some nice foreach enumerators.
|
||||||
|
@ -103,286 +99,33 @@ namespace nv
|
||||||
NV_FORCEINLINE bool isNull() const { return m_buffer == NULL; }
|
NV_FORCEINLINE bool isNull() const { return m_buffer == NULL; }
|
||||||
|
|
||||||
|
|
||||||
/// Push an element at the end of the vector.
|
void push_back( const T & val );
|
||||||
NV_FORCEINLINE void push_back( const T & val )
|
void pushBack( const T & val );
|
||||||
{
|
void append( const T & val );
|
||||||
#if 1
|
Array<T> & operator<< ( T & t );
|
||||||
nvDebugCheck(&val < m_buffer || &val > m_buffer+m_size);
|
void pop_back();
|
||||||
|
void popBack();
|
||||||
uint old_size = m_size;
|
const T & back() const;
|
||||||
uint new_size = m_size + 1;
|
T & back();
|
||||||
|
const T & front() const;
|
||||||
setArraySize(new_size);
|
T & front();
|
||||||
|
bool contains(const T & e) const;
|
||||||
construct_range(m_buffer, new_size, old_size, val);
|
bool find(const T & element, uint * indexPtr) const;
|
||||||
#else
|
bool find(const T & element, uint begin, uint end, uint * indexPtr) const;
|
||||||
uint new_size = m_size + 1;
|
void removeAt(uint index);
|
||||||
|
bool remove(const T & element);
|
||||||
if (new_size > m_capacity)
|
void insertAt(uint index, const T & val = T());
|
||||||
{
|
void append(const Array<T> & other);
|
||||||
// @@ Is there any way to avoid this copy?
|
void append(const T other[], uint count);
|
||||||
// @@ Can we create a copy without side effects? Ie. without calls to constructor/destructor. Use alloca + memcpy?
|
void replaceWithLast(uint index);
|
||||||
// @@ Assert instead of copy?
|
void resize(uint new_size);
|
||||||
const T copy(val); // create a copy in case value is inside of this array.
|
void resize(uint new_size, const T & elem);
|
||||||
|
void clear();
|
||||||
setArraySize(new_size);
|
void shrink();
|
||||||
|
void reserve(uint desired_size);
|
||||||
new (m_buffer+new_size-1) T(copy);
|
void copy(const T * data, uint count);
|
||||||
}
|
Array<T> & operator=( const Array<T> & a );
|
||||||
else
|
T * release();
|
||||||
{
|
|
||||||
m_size = new_size;
|
|
||||||
new(m_buffer+new_size-1) T(val);
|
|
||||||
}
|
|
||||||
#endif // 0/1
|
|
||||||
}
|
|
||||||
NV_FORCEINLINE void pushBack( const T & val )
|
|
||||||
{
|
|
||||||
push_back(val);
|
|
||||||
}
|
|
||||||
NV_FORCEINLINE void append( const T & val )
|
|
||||||
{
|
|
||||||
push_back(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Qt like push operator.
|
|
||||||
NV_FORCEINLINE Array<T> & operator<< ( T & t )
|
|
||||||
{
|
|
||||||
push_back(t);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pop the element at the end of the vector.
|
|
||||||
NV_FORCEINLINE void pop_back()
|
|
||||||
{
|
|
||||||
nvDebugCheck( m_size > 0 );
|
|
||||||
resize( m_size - 1 );
|
|
||||||
}
|
|
||||||
NV_FORCEINLINE void popBack()
|
|
||||||
{
|
|
||||||
pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get back element.
|
|
||||||
NV_FORCEINLINE const T & back() const
|
|
||||||
{
|
|
||||||
nvDebugCheck( m_size > 0 );
|
|
||||||
return m_buffer[m_size-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get back element.
|
|
||||||
NV_FORCEINLINE T & back()
|
|
||||||
{
|
|
||||||
nvDebugCheck( m_size > 0 );
|
|
||||||
return m_buffer[m_size-1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get front element.
|
|
||||||
NV_FORCEINLINE const T & front() const
|
|
||||||
{
|
|
||||||
nvDebugCheck( m_size > 0 );
|
|
||||||
return m_buffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get front element.
|
|
||||||
NV_FORCEINLINE T & front()
|
|
||||||
{
|
|
||||||
nvDebugCheck( m_size > 0 );
|
|
||||||
return m_buffer[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the given element is contained in the array.
|
|
||||||
NV_FORCEINLINE bool contains(const T & e) const
|
|
||||||
{
|
|
||||||
return find(e, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if element found.
|
|
||||||
NV_FORCEINLINE bool find(const T & element, uint * indexPtr) const
|
|
||||||
{
|
|
||||||
return find(element, 0, m_size, indexPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return true if element found within the given range.
|
|
||||||
NV_FORCEINLINE bool find(const T & element, uint begin, uint end, uint * indexPtr) const
|
|
||||||
{
|
|
||||||
return ::nv::find(element, m_buffer, begin, end, indexPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove the element at the given index. This is an expensive operation!
|
|
||||||
void removeAt(uint index)
|
|
||||||
{
|
|
||||||
nvDebugCheck(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.
|
|
||||||
bool remove(const T & element)
|
|
||||||
{
|
|
||||||
uint index;
|
|
||||||
if (find(element, &index)) {
|
|
||||||
removeAt(index);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Insert the given element at the given index shifting all the elements up.
|
|
||||||
void insertAt(uint index, const T & val = T())
|
|
||||||
{
|
|
||||||
nvDebugCheck( index >= 0 && index <= m_size );
|
|
||||||
|
|
||||||
setArraySize(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.
|
|
||||||
NV_FORCEINLINE 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;
|
|
||||||
|
|
||||||
setArraySize(m_size + count);
|
|
||||||
|
|
||||||
for (uint i = 0; i < count; i++ ) {
|
|
||||||
new(m_buffer + old_size + i) T(other[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Remove the given element by replacing it with the last one.
|
|
||||||
void replaceWithLast(uint index)
|
|
||||||
{
|
|
||||||
nvDebugCheck( index < m_size );
|
|
||||||
nv::swap(m_buffer[index], back());
|
|
||||||
(m_buffer+m_size-1)->~T();
|
|
||||||
m_size--;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Resize the vector preserving existing elements.
|
|
||||||
void resize(uint new_size)
|
|
||||||
{
|
|
||||||
uint old_size = m_size;
|
|
||||||
|
|
||||||
// Destruct old elements (if we're shrinking).
|
|
||||||
destroy_range(m_buffer, new_size, old_size);
|
|
||||||
|
|
||||||
setArraySize(new_size);
|
|
||||||
|
|
||||||
// Call default constructors
|
|
||||||
construct_range(m_buffer, new_size, old_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Resize the vector preserving existing elements and initializing the
|
|
||||||
/// new ones with the given value.
|
|
||||||
void resize(uint new_size, const T & elem)
|
|
||||||
{
|
|
||||||
nvDebugCheck(&elem < m_buffer || &elem > m_buffer+m_size);
|
|
||||||
|
|
||||||
uint old_size = m_size;
|
|
||||||
|
|
||||||
// Destruct old elements (if we're shrinking).
|
|
||||||
destroy_range(m_buffer, new_size, old_size);
|
|
||||||
|
|
||||||
setArraySize(new_size);
|
|
||||||
|
|
||||||
// Call copy constructors
|
|
||||||
construct_range(m_buffer, new_size, old_size, elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Clear the buffer.
|
|
||||||
NV_FORCEINLINE void clear()
|
|
||||||
{
|
|
||||||
// Destruct old elements
|
|
||||||
destroy_range(m_buffer, 0, m_size);
|
|
||||||
|
|
||||||
m_size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shrink the allocated vector.
|
|
||||||
NV_FORCEINLINE void shrink()
|
|
||||||
{
|
|
||||||
if (m_size < m_capacity) {
|
|
||||||
setArrayCapacity(m_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Preallocate space.
|
|
||||||
NV_FORCEINLINE void reserve(uint desired_size)
|
|
||||||
{
|
|
||||||
if (desired_size > m_capacity) {
|
|
||||||
setArrayCapacity(desired_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copy elements to this array. Resizes it if needed.
|
|
||||||
NV_FORCEINLINE void copy(const T * data, uint count)
|
|
||||||
{
|
|
||||||
destroy_range(m_buffer, count, m_size);
|
|
||||||
|
|
||||||
setArraySize(count);
|
|
||||||
|
|
||||||
::nv::copy(m_buffer, data, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Assignment operator.
|
|
||||||
NV_FORCEINLINE Array<T> & operator=( const Array<T> & a )
|
|
||||||
{
|
|
||||||
copy(a.m_buffer, a.m_size);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release ownership of allocated memory and returns pointer to it.
|
|
||||||
T * release() {
|
|
||||||
T * tmp = m_buffer;
|
|
||||||
m_buffer = NULL;
|
|
||||||
m_capacity = 0;
|
|
||||||
m_size = 0;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
// Array enumerator.
|
||||||
|
@ -401,55 +144,18 @@ namespace nv
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Swap the members of this vector and the given vector.
|
// Friends.
|
||||||
friend void swapMembers(Array & a, Array & b)
|
template <typename Typ>
|
||||||
{
|
friend Stream & operator<< ( Stream & s, Array<Typ> & p );
|
||||||
nv::swap(a.m_buffer, b.m_buffer);
|
|
||||||
nv::swap(a.m_capacity, b.m_capacity);
|
template <typename Typ>
|
||||||
nv::swap(a.m_size, b.m_size);
|
friend void swap(Array<Typ> & a, Array<Typ> & b);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Change array size.
|
void setArraySize(uint new_size);
|
||||||
void setArraySize(uint new_size) {
|
void setArrayCapacity(uint new_capacity);
|
||||||
m_size = new_size;
|
|
||||||
|
|
||||||
if (new_size > m_capacity) {
|
|
||||||
uint new_buffer_size;
|
|
||||||
if (m_capacity == 0) {
|
|
||||||
// first allocation is exact
|
|
||||||
new_buffer_size = new_size;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// following allocations grow array by 25%
|
|
||||||
new_buffer_size = new_size + (new_size >> 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
setArrayCapacity( new_buffer_size );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Change array capacity.
|
|
||||||
void setArrayCapacity(uint new_capacity) {
|
|
||||||
nvDebugCheck(new_capacity >= m_size);
|
|
||||||
|
|
||||||
if (new_capacity == 0) {
|
|
||||||
// free the buffer.
|
|
||||||
if (m_buffer != NULL) {
|
|
||||||
free<T>(m_buffer);
|
|
||||||
m_buffer = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// realloc the buffer
|
|
||||||
m_buffer = realloc<T>(m_buffer, new_capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_capacity = new_capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
T * m_buffer;
|
T * m_buffer;
|
||||||
uint m_capacity;
|
uint m_capacity;
|
||||||
|
@ -457,13 +163,6 @@ protected:
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void swap(Array<T> & a, Array<T> & b)
|
|
||||||
{
|
|
||||||
swapMembers(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
|
|
383
trunk/src/nvcore/Array.inl
Executable file
383
trunk/src/nvcore/Array.inl
Executable file
|
@ -0,0 +1,383 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_ARRAY_INL
|
||||||
|
#define NV_CORE_ARRAY_INL
|
||||||
|
|
||||||
|
#include "Array.h"
|
||||||
|
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "Utils.h" // swap
|
||||||
|
|
||||||
|
#include <string.h> // memmove
|
||||||
|
#include <new> // for placement new
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
|
||||||
|
// Push an element at the end of the vector.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::push_back( const T & val )
|
||||||
|
{
|
||||||
|
#if 1
|
||||||
|
nvDebugCheck(&val < m_buffer || &val > m_buffer+m_size);
|
||||||
|
|
||||||
|
uint old_size = m_size;
|
||||||
|
uint new_size = m_size + 1;
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
construct_range(m_buffer, new_size, old_size, val);
|
||||||
|
#else
|
||||||
|
uint new_size = m_size + 1;
|
||||||
|
|
||||||
|
if (new_size > m_capacity)
|
||||||
|
{
|
||||||
|
// @@ Is there any way to avoid this copy?
|
||||||
|
// @@ Can we create a copy without side effects? Ie. without calls to constructor/destructor. Use alloca + memcpy?
|
||||||
|
// @@ Assert instead of copy?
|
||||||
|
const T copy(val); // create a copy in case value is inside of this array.
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
new (m_buffer+new_size-1) T(copy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_size = new_size;
|
||||||
|
new(m_buffer+new_size-1) T(val);
|
||||||
|
}
|
||||||
|
#endif // 0/1
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::pushBack( const T & val )
|
||||||
|
{
|
||||||
|
push_back(val);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::append( const T & val )
|
||||||
|
{
|
||||||
|
push_back(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Qt like push operator.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE Array<T> & Array<T>::operator<< ( T & t )
|
||||||
|
{
|
||||||
|
push_back(t);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop the element at the end of the vector.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::pop_back()
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
resize( m_size - 1 );
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::popBack()
|
||||||
|
{
|
||||||
|
pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get back element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE const T & Array<T>::back() const
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[m_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get back element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE T & Array<T>::back()
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[m_size-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get front element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE const T & Array<T>::front() const
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get front element.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE T & Array<T>::front()
|
||||||
|
{
|
||||||
|
nvDebugCheck( m_size > 0 );
|
||||||
|
return m_buffer[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the given element is contained in the array.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE bool Array<T>::contains(const T & e) const
|
||||||
|
{
|
||||||
|
return find(e, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if element found.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE bool Array<T>::find(const T & element, uint * indexPtr) const
|
||||||
|
{
|
||||||
|
return find(element, 0, m_size, indexPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if element found within the given range.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE bool Array<T>::find(const T & element, uint begin, uint end, uint * indexPtr) const
|
||||||
|
{
|
||||||
|
return ::nv::find(element, m_buffer, begin, end, indexPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the element at the given index. This is an expensive operation!
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::removeAt(uint index)
|
||||||
|
{
|
||||||
|
nvDebugCheck(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.
|
||||||
|
template <typename T>
|
||||||
|
bool Array<T>::remove(const T & element)
|
||||||
|
{
|
||||||
|
uint index;
|
||||||
|
if (find(element, &index)) {
|
||||||
|
removeAt(index);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the given element at the given index shifting all the elements up.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::insertAt(uint index, const T & val/*=T()*/)
|
||||||
|
{
|
||||||
|
nvDebugCheck( index >= 0 && index <= m_size );
|
||||||
|
|
||||||
|
setArraySize(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.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::append(const Array<T> & other)
|
||||||
|
{
|
||||||
|
append(other.m_buffer, other.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append the given data to our vector.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::append(const T other[], uint count)
|
||||||
|
{
|
||||||
|
if (count > 0) {
|
||||||
|
const uint old_size = m_size;
|
||||||
|
|
||||||
|
setArraySize(m_size + count);
|
||||||
|
|
||||||
|
for (uint i = 0; i < count; i++ ) {
|
||||||
|
new(m_buffer + old_size + i) T(other[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove the given element by replacing it with the last one.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::replaceWithLast(uint index)
|
||||||
|
{
|
||||||
|
nvDebugCheck( index < m_size );
|
||||||
|
nv::swap(m_buffer[index], back());
|
||||||
|
(m_buffer+m_size-1)->~T();
|
||||||
|
m_size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize the vector preserving existing elements.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::resize(uint new_size)
|
||||||
|
{
|
||||||
|
uint old_size = m_size;
|
||||||
|
|
||||||
|
// Destruct old elements (if we're shrinking).
|
||||||
|
destroy_range(m_buffer, new_size, old_size);
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
// Call default constructors
|
||||||
|
construct_range(m_buffer, new_size, old_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Resize the vector preserving existing elements and initializing the
|
||||||
|
// new ones with the given value.
|
||||||
|
template <typename T>
|
||||||
|
void Array<T>::resize(uint new_size, const T & elem)
|
||||||
|
{
|
||||||
|
nvDebugCheck(&elem < m_buffer || &elem > m_buffer+m_size);
|
||||||
|
|
||||||
|
uint old_size = m_size;
|
||||||
|
|
||||||
|
// Destruct old elements (if we're shrinking).
|
||||||
|
destroy_range(m_buffer, new_size, old_size);
|
||||||
|
|
||||||
|
setArraySize(new_size);
|
||||||
|
|
||||||
|
// Call copy constructors
|
||||||
|
construct_range(m_buffer, new_size, old_size, elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the buffer.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::clear()
|
||||||
|
{
|
||||||
|
// Destruct old elements
|
||||||
|
destroy_range(m_buffer, 0, m_size);
|
||||||
|
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shrink the allocated vector.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::shrink()
|
||||||
|
{
|
||||||
|
if (m_size < m_capacity) {
|
||||||
|
setArrayCapacity(m_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preallocate space.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::reserve(uint desired_size)
|
||||||
|
{
|
||||||
|
if (desired_size > m_capacity) {
|
||||||
|
setArrayCapacity(desired_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy elements to this array. Resizes it if needed.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE void Array<T>::copy(const T * data, uint count)
|
||||||
|
{
|
||||||
|
destroy_range(m_buffer, count, m_size);
|
||||||
|
|
||||||
|
setArraySize(count);
|
||||||
|
|
||||||
|
::nv::copy(m_buffer, data, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assignment operator.
|
||||||
|
template <typename T>
|
||||||
|
NV_FORCEINLINE Array<T> & Array<T>::operator=( const Array<T> & a )
|
||||||
|
{
|
||||||
|
copy(a.m_buffer, a.m_size);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release ownership of allocated memory and returns pointer to it.
|
||||||
|
template <typename T>
|
||||||
|
T * Array<T>::release() {
|
||||||
|
T * tmp = m_buffer;
|
||||||
|
m_buffer = NULL;
|
||||||
|
m_capacity = 0;
|
||||||
|
m_size = 0;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Change array size.
|
||||||
|
template <typename T>
|
||||||
|
inline void Array<T>::setArraySize(uint new_size) {
|
||||||
|
m_size = new_size;
|
||||||
|
|
||||||
|
if (new_size > m_capacity) {
|
||||||
|
uint new_buffer_size;
|
||||||
|
if (m_capacity == 0) {
|
||||||
|
// first allocation is exact
|
||||||
|
new_buffer_size = new_size;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// following allocations grow array by 25%
|
||||||
|
new_buffer_size = new_size + (new_size >> 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
setArrayCapacity( new_buffer_size );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Change array capacity.
|
||||||
|
template <typename T>
|
||||||
|
inline void Array<T>::setArrayCapacity(uint new_capacity) {
|
||||||
|
nvDebugCheck(new_capacity >= m_size);
|
||||||
|
|
||||||
|
if (new_capacity == 0) {
|
||||||
|
// free the buffer.
|
||||||
|
if (m_buffer != NULL) {
|
||||||
|
free<T>(m_buffer);
|
||||||
|
m_buffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// realloc the buffer
|
||||||
|
m_buffer = realloc<T>(m_buffer, new_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_capacity = new_capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array serialization.
|
||||||
|
template <typename Typ>
|
||||||
|
inline Stream & operator<< ( Stream & s, Array<Typ> & 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap the members of the two given vectors.
|
||||||
|
template <typename Typ>
|
||||||
|
inline void swap(Array<Typ> & a, Array<Typ> & b)
|
||||||
|
{
|
||||||
|
nv::swap(a.m_buffer, b.m_buffer);
|
||||||
|
nv::swap(a.m_capacity, b.m_capacity);
|
||||||
|
nv::swap(a.m_size, b.m_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_ARRAY_INL
|
|
@ -6,9 +6,8 @@
|
||||||
|
|
||||||
#include "nvcore.h"
|
#include "nvcore.h"
|
||||||
|
|
||||||
#if defined(HAVE_STDARG_H)
|
#include <stdarg.h> // va_list
|
||||||
# include <stdarg.h> // va_list
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Make sure we are using our assert.
|
// Make sure we are using our assert.
|
||||||
#undef assert
|
#undef assert
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h> // uint8_t, int8_t, ... uintptr_t
|
#include <stdint.h> // uint8_t, int8_t, ... uintptr_t
|
||||||
//#include <cstddef> // operator new, size_t, NULL
|
#include <stddef.h> // operator new, size_t, NULL
|
||||||
|
|
||||||
// Function linkage
|
// Function linkage
|
||||||
#define DLL_IMPORT
|
#define DLL_IMPORT
|
||||||
|
|
|
@ -81,3 +81,6 @@ typedef uint32 uint;
|
||||||
|
|
||||||
#pragma warning(disable : 4675) // resolved overload was found by argument-dependent lookup
|
#pragma warning(disable : 4675) // resolved overload was found by argument-dependent lookup
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma warning(1 : 4705) // Report unused local variables.
|
||||||
|
#pragma warning(1 : 4555) // Expression has no effect.
|
||||||
|
|
|
@ -8,10 +8,8 @@
|
||||||
These foreach macros are very non-standard and somewhat confusing, but I like them.
|
These foreach macros are very non-standard and somewhat confusing, but I like them.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "nvcore.h"
|
#include "nvcore.h"
|
||||||
|
|
||||||
|
|
||||||
#if NV_CC_GNUC // If typeof is available:
|
#if NV_CC_GNUC // If typeof is available:
|
||||||
|
|
||||||
#define NV_FOREACH(i, container) \
|
#define NV_FOREACH(i, container) \
|
||||||
|
@ -24,6 +22,8 @@ for(typename typeof(container)::PseudoIndex i((container).start()); !(container)
|
||||||
|
|
||||||
#else // If typeof not available:
|
#else // If typeof not available:
|
||||||
|
|
||||||
|
#include <new> // placement new
|
||||||
|
|
||||||
struct PseudoIndexWrapper {
|
struct PseudoIndexWrapper {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
PseudoIndexWrapper(const T & container) {
|
PseudoIndexWrapper(const T & container) {
|
||||||
|
|
65
trunk/src/nvcore/Hash.h
Executable file
65
trunk/src/nvcore/Hash.h
Executable file
|
@ -0,0 +1,65 @@
|
||||||
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef NV_CORE_HASH_H
|
||||||
|
#define NV_CORE_HASH_H
|
||||||
|
|
||||||
|
#include "nvcore.h"
|
||||||
|
|
||||||
|
namespace nv
|
||||||
|
{
|
||||||
|
inline uint sdbmHash(const void * data_in, uint size, uint h = 5381)
|
||||||
|
{
|
||||||
|
const uint8 * data = (const uint8 *) data_in;
|
||||||
|
uint i = 0;
|
||||||
|
while (i < size) {
|
||||||
|
h = (h << 16) + (h << 6) - h + (uint) data[i++];
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note that this hash does not handle NaN properly.
|
||||||
|
inline uint sdbmFloatHash(const float * f, uint count, uint h = 5381)
|
||||||
|
{
|
||||||
|
for (uint i = 0; i < count; i++) {
|
||||||
|
//nvDebugCheck(nv::isFinite(*f));
|
||||||
|
union { float f; uint32 i; } x = { f[i] };
|
||||||
|
if (x.i == 0x80000000) x.i = 0;
|
||||||
|
h = sdbmHash(&x, 4, h);
|
||||||
|
}
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Some hash functors:
|
||||||
|
template <typename Key> struct Hash
|
||||||
|
{
|
||||||
|
uint operator()(const Key & k) const {
|
||||||
|
return sdbmHash(&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 <> struct Hash<float>
|
||||||
|
{
|
||||||
|
uint operator()(float f) const {
|
||||||
|
return sdbmFloatHash(&f, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Key> struct Equal
|
||||||
|
{
|
||||||
|
bool operator()(const Key & k0, const Key & k1) const {
|
||||||
|
return k0 == k1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nv namespace
|
||||||
|
|
||||||
|
#endif // NV_CORE_HASH_H
|
|
@ -7,9 +7,9 @@
|
||||||
#include "nvcore.h"
|
#include "nvcore.h"
|
||||||
|
|
||||||
#include <stdlib.h> // malloc(), realloc() and free()
|
#include <stdlib.h> // malloc(), realloc() and free()
|
||||||
#include <stddef.h> // size_t
|
//#include <stddef.h> // size_t
|
||||||
|
|
||||||
#include <new> // new and delete
|
//#include <new> // new and delete
|
||||||
|
|
||||||
|
|
||||||
#if NV_CC_GNUC
|
#if NV_CC_GNUC
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
// This code is in the public domain -- Ignacio Castaño <castano@gmail.com>
|
||||||
|
|
||||||
#pragma once
|
//#pragma once
|
||||||
#ifndef NV_CORE_STDSTREAM_H
|
//#ifndef NV_CORE_STDSTREAM_H
|
||||||
#define NV_CORE_STDSTREAM_H
|
//#define NV_CORE_STDSTREAM_H
|
||||||
|
|
||||||
#include "nvcore.h"
|
#include "nvcore.h"
|
||||||
#include "Stream.h"
|
#include "Stream.h"
|
||||||
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
#include <stdio.h> // fopen
|
#include <stdio.h> // fopen
|
||||||
#include <string.h> // memcpy
|
#include <string.h> // memcpy
|
||||||
#include <exception> // std::exception
|
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
|
@ -378,7 +377,7 @@ namespace nv
|
||||||
len = m_s->serialize( data, len );
|
len = m_s->serialize( data, len );
|
||||||
|
|
||||||
if( m_s->isError() ) {
|
if( m_s->isError() ) {
|
||||||
throw std::exception();
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
|
@ -389,7 +388,7 @@ namespace nv
|
||||||
m_s->seek( pos );
|
m_s->seek( pos );
|
||||||
|
|
||||||
if( m_s->isError() ) {
|
if( m_s->isError() ) {
|
||||||
throw std::exception();
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,4 +444,4 @@ namespace nv
|
||||||
} // nv namespace
|
} // nv namespace
|
||||||
|
|
||||||
|
|
||||||
#endif // NV_CORE_STDSTREAM_H
|
//#endif // NV_CORE_STDSTREAM_H
|
||||||
|
|
|
@ -2,8 +2,12 @@
|
||||||
|
|
||||||
#include "StrLib.h"
|
#include "StrLib.h"
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Utils.h" // swap
|
||||||
|
|
||||||
#include <math.h> // log
|
#include <math.h> // log
|
||||||
#include <stdio.h> // vsnprintf
|
#include <stdio.h> // vsnprintf
|
||||||
|
#include <string.h> // strlen, strcmp, etc.
|
||||||
|
|
||||||
#if NV_CC_MSVC
|
#if NV_CC_MSVC
|
||||||
#include <stdarg.h> // vsnprintf
|
#include <stdarg.h> // vsnprintf
|
||||||
|
@ -66,6 +70,12 @@ namespace
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint nv::strLen(const char * str)
|
||||||
|
{
|
||||||
|
nvDebugCheck(str != NULL);
|
||||||
|
return toU32(strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
int nv::strCmp(const char * s1, const char * s2)
|
int nv::strCmp(const char * s1, const char * s2)
|
||||||
{
|
{
|
||||||
nvDebugCheck(s1 != NULL);
|
nvDebugCheck(s1 != NULL);
|
||||||
|
@ -84,7 +94,28 @@ int nv::strCaseCmp(const char * s1, const char * s2)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void nv::strCpy(char * dst, int size, const char * src)
|
bool nv::strEqual(const char * s1, const char * s2)
|
||||||
|
{
|
||||||
|
if (s1 == s2) return true;
|
||||||
|
if (s1 == NULL || s2 == NULL) return false;
|
||||||
|
return strCmp(s1, s2) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nv::strBeginsWith(const char * dst, const char * prefix)
|
||||||
|
{
|
||||||
|
//return strstr(dst, prefix) == dst;
|
||||||
|
return strncmp(dst, prefix, strlen(prefix)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @@ Not tested.
|
||||||
|
bool nv::strEndsWith(const char * dst, const char * suffix)
|
||||||
|
{
|
||||||
|
const size_t len = strlen(suffix);
|
||||||
|
return strncmp(dst + strlen(dst) - len, suffix, len) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void nv::strCpy(char * dst, uint size, const char * src)
|
||||||
{
|
{
|
||||||
nvDebugCheck(dst != NULL);
|
nvDebugCheck(dst != NULL);
|
||||||
nvDebugCheck(src != NULL);
|
nvDebugCheck(src != NULL);
|
||||||
|
@ -96,7 +127,7 @@ void nv::strCpy(char * dst, int size, const char * src)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void nv::strCpy(char * dst, int size, const char * src, int len)
|
void nv::strCpy(char * dst, uint size, const char * src, uint len)
|
||||||
{
|
{
|
||||||
nvDebugCheck(dst != NULL);
|
nvDebugCheck(dst != NULL);
|
||||||
nvDebugCheck(src != NULL);
|
nvDebugCheck(src != NULL);
|
||||||
|
@ -108,7 +139,7 @@ void nv::strCpy(char * dst, int size, const char * src, int len)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void nv::strCat(char * dst, int size, const char * src)
|
void nv::strCat(char * dst, uint size, const char * src)
|
||||||
{
|
{
|
||||||
nvDebugCheck(dst != NULL);
|
nvDebugCheck(dst != NULL);
|
||||||
nvDebugCheck(src != NULL);
|
nvDebugCheck(src != NULL);
|
||||||
|
@ -468,6 +499,13 @@ char * StringBuilder::release()
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Swap strings.
|
||||||
|
void nv::swap(StringBuilder & a, StringBuilder & b) {
|
||||||
|
swap(a.m_size, b.m_size);
|
||||||
|
swap(a.m_str, b.m_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
|
||||||
{
|
{
|
||||||
|
@ -604,7 +642,7 @@ void String::setString(const char * str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void String::setString(const char * str, int length)
|
void String::setString(const char * str, uint length)
|
||||||
{
|
{
|
||||||
nvDebugCheck(str != NULL);
|
nvDebugCheck(str != NULL);
|
||||||
|
|
||||||
|
@ -622,3 +660,44 @@ void String::setString(const StringBuilder & str)
|
||||||
addRef();
|
addRef();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add reference count.
|
||||||
|
void String::addRef()
|
||||||
|
{
|
||||||
|
if (data != NULL)
|
||||||
|
{
|
||||||
|
setRefCount(getRefCount() + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrease reference count.
|
||||||
|
void String::release()
|
||||||
|
{
|
||||||
|
if (data != NULL)
|
||||||
|
{
|
||||||
|
const uint16 count = getRefCount();
|
||||||
|
setRefCount(count - 1);
|
||||||
|
if (count - 1 == 0) {
|
||||||
|
free(data - 2);
|
||||||
|
data = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void String::allocString(const char * str, uint len)
|
||||||
|
{
|
||||||
|
const char * ptr = malloc<char>(2 + len + 1);
|
||||||
|
|
||||||
|
setData( ptr );
|
||||||
|
setRefCount( 0 );
|
||||||
|
|
||||||
|
// Copy string.
|
||||||
|
strCpy(const_cast<char *>(data), len+1, str, len);
|
||||||
|
|
||||||
|
// Add terminating character.
|
||||||
|
const_cast<char *>(data)[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void nv::swap(String & a, String & b) {
|
||||||
|
swap(a.data, b.data);
|
||||||
|
}
|
||||||
|
|
|
@ -4,11 +4,10 @@
|
||||||
#ifndef NV_CORE_STRING_H
|
#ifndef NV_CORE_STRING_H
|
||||||
#define NV_CORE_STRING_H
|
#define NV_CORE_STRING_H
|
||||||
|
|
||||||
#include "nvcore.h"
|
#include "Debug.h"
|
||||||
#include "Memory.h"
|
#include "Hash.h" // hash
|
||||||
#include "Utils.h" // swap, hash
|
|
||||||
|
|
||||||
#include <string.h> // strlen, strcmp, etc.
|
//#include <string.h> // strlen, etc.
|
||||||
|
|
||||||
#if NV_OS_WIN32
|
#if NV_OS_WIN32
|
||||||
#define NV_PATH_SEPARATOR '\\'
|
#define NV_PATH_SEPARATOR '\\'
|
||||||
|
@ -19,7 +18,7 @@
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
|
|
||||||
uint strHash(const char * str, uint h) NV_PURE;
|
NVCORE_API uint strHash(const char * str, uint h) NV_PURE;
|
||||||
|
|
||||||
/// String hash based on Bernstein's hash.
|
/// String hash based on Bernstein's hash.
|
||||||
inline uint strHash(const char * data, uint h = 5381)
|
inline uint strHash(const char * data, uint h = 5381)
|
||||||
|
@ -37,18 +36,23 @@ namespace nv
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
NVCORE_API uint strLen(const char * str) NV_PURE;
|
||||||
|
|
||||||
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;
|
||||||
|
NVCORE_API bool strEqual(const char * s1, const char * s2) NV_PURE; // Accepts NULL strings.
|
||||||
|
|
||||||
template <> struct Equal<const char *> {
|
template <> struct Equal<const char *> {
|
||||||
bool operator()(const char * a, const char * b) const { return strCmp(a, b) == 0; }
|
bool operator()(const char * a, const char * b) const { return strEqual(a, b); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
NVCORE_API bool strBeginsWith(const char * dst, const char * prefix) NV_PURE;
|
||||||
|
NVCORE_API bool strEndsWith(const char * dst, const char * suffix) NV_PURE;
|
||||||
|
|
||||||
NVCORE_API void strCpy(char * dst, int size, const char * src);
|
|
||||||
NVCORE_API void strCpy(char * dst, int size, const char * src, int len);
|
NVCORE_API void strCpy(char * dst, uint size, const char * src);
|
||||||
NVCORE_API void strCat(char * dst, int size, const char * src);
|
NVCORE_API void strCpy(char * dst, uint size, const char * src, uint len);
|
||||||
|
NVCORE_API void strCat(char * dst, uint size, const char * src);
|
||||||
|
|
||||||
NVCORE_API bool strMatch(const char * str, const char * pat) NV_PURE;
|
NVCORE_API bool strMatch(const char * str, const char * pat) NV_PURE;
|
||||||
|
|
||||||
|
@ -110,13 +114,11 @@ namespace nv
|
||||||
|
|
||||||
/// Equal operator.
|
/// Equal operator.
|
||||||
bool operator==( const StringBuilder & s ) const {
|
bool operator==( const StringBuilder & s ) const {
|
||||||
if (s.isNull()) return isNull();
|
return strMatch(s.m_str, m_str);
|
||||||
else if (isNull()) return false;
|
|
||||||
else return strcmp(s.m_str, m_str) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the exact length.
|
/// Return the exact length.
|
||||||
uint length() const { return isNull() ? 0 : uint(strlen(m_str)); }
|
uint length() const { return isNull() ? 0 : strLen(m_str); }
|
||||||
|
|
||||||
/// Return the size of the string container.
|
/// Return the size of the string container.
|
||||||
uint capacity() const { return m_size; }
|
uint capacity() const { return m_size; }
|
||||||
|
@ -124,11 +126,8 @@ namespace nv
|
||||||
/// Return the hash of the string.
|
/// Return the hash of the string.
|
||||||
uint hash() const { return isNull() ? 0 : strHash(m_str); }
|
uint hash() const { return isNull() ? 0 : strHash(m_str); }
|
||||||
|
|
||||||
/// Swap strings.
|
// Swap strings.
|
||||||
friend void swap(StringBuilder & a, StringBuilder & b) {
|
friend void swap(StringBuilder & a, StringBuilder & b);
|
||||||
nv::swap(a.m_size, b.m_size);
|
|
||||||
nv::swap(a.m_str, b.m_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -242,52 +241,32 @@ namespace nv
|
||||||
/// Equal operator.
|
/// Equal operator.
|
||||||
bool operator==( const String & str ) const
|
bool operator==( const String & str ) const
|
||||||
{
|
{
|
||||||
if( str.data == data ) {
|
return strMatch(str.data, data);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if ((data == NULL) != (str.data == NULL)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return strcmp(data, str.data) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Equal operator.
|
/// Equal operator.
|
||||||
bool operator==( const char * str ) const
|
bool operator==( const char * str ) const
|
||||||
{
|
{
|
||||||
nvCheck(str != NULL); // Use isNull!
|
return strMatch(str, data);
|
||||||
if (data == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return strcmp(data, str) == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Not equal operator.
|
/// Not equal operator.
|
||||||
bool operator!=( const String & str ) const
|
bool operator!=( const String & str ) const
|
||||||
{
|
{
|
||||||
if( str.data == data ) {
|
return !strMatch(str.data, data);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((data == NULL) != (str.data == NULL)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return strcmp(data, str.data) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Not equal operator.
|
/// Not equal operator.
|
||||||
bool operator!=( const char * str ) const
|
bool operator!=( const char * str ) const
|
||||||
{
|
{
|
||||||
nvCheck(str != NULL); // Use isNull!
|
return !strMatch(str, data);
|
||||||
if (data == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return strcmp(data, str) != 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this string is the null string.
|
/// Returns true if this string is the null string.
|
||||||
bool isNull() const { return data == NULL; }
|
bool isNull() const { return data == NULL; }
|
||||||
|
|
||||||
/// Return the exact length.
|
/// Return the exact length.
|
||||||
uint length() const { nvDebugCheck(data != NULL); return uint(strlen(data)); }
|
uint length() const { nvDebugCheck(data != NULL); return strLen(data); }
|
||||||
|
|
||||||
/// Return the hash of the string.
|
/// Return the hash of the string.
|
||||||
uint hash() const { nvDebugCheck(data != NULL); return strHash(data); }
|
uint hash() const { nvDebugCheck(data != NULL); return strHash(data); }
|
||||||
|
@ -302,27 +281,10 @@ namespace nv
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Add reference count.
|
// Add reference count.
|
||||||
void addRef()
|
void addRef();
|
||||||
{
|
|
||||||
if (data != NULL)
|
|
||||||
{
|
|
||||||
setRefCount(getRefCount() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decrease reference count.
|
// Decrease reference count.
|
||||||
void release()
|
void release();
|
||||||
{
|
|
||||||
if (data != NULL)
|
|
||||||
{
|
|
||||||
const uint16 count = getRefCount();
|
|
||||||
setRefCount(count - 1);
|
|
||||||
if (count - 1 == 0) {
|
|
||||||
free(data - 2);
|
|
||||||
data = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16 getRefCount() const
|
uint16 getRefCount() const
|
||||||
{
|
{
|
||||||
|
@ -342,31 +304,17 @@ namespace nv
|
||||||
|
|
||||||
void allocString(const char * str)
|
void allocString(const char * str)
|
||||||
{
|
{
|
||||||
allocString(str, (int)strlen(str));
|
allocString(str, strLen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
void allocString(const char * str, int len)
|
void allocString(const char * str, uint length);
|
||||||
{
|
|
||||||
const char * ptr = malloc<char>(2 + len + 1);
|
|
||||||
|
|
||||||
setData( ptr );
|
|
||||||
setRefCount( 0 );
|
|
||||||
|
|
||||||
// Copy string.
|
|
||||||
strCpy(const_cast<char *>(data), len+1, str, len);
|
|
||||||
|
|
||||||
// Add terminating character.
|
|
||||||
const_cast<char *>(data)[len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void setString(const char * str);
|
void setString(const char * str);
|
||||||
void setString(const char * str, int length);
|
void setString(const char * str, uint length);
|
||||||
void setString(const StringBuilder & str);
|
void setString(const StringBuilder & str);
|
||||||
|
|
||||||
/// Swap strings.
|
// Swap strings.
|
||||||
friend void swap(String & a, String & b) {
|
friend void swap(String & a, String & b);
|
||||||
swap(a.data, b.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ TextWriter::TextWriter(Stream * s) :
|
||||||
void TextWriter::writeString(const char * str)
|
void TextWriter::writeString(const char * str)
|
||||||
{
|
{
|
||||||
nvDebugCheck(s != NULL);
|
nvDebugCheck(s != NULL);
|
||||||
s->serialize(const_cast<char *>(str), (int)strlen(str));
|
s->serialize(const_cast<char *>(str), strLen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextWriter::writeString(const char * str, uint len)
|
void TextWriter::writeString(const char * str, uint len)
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
#ifndef NV_CORE_UTILS_H
|
#ifndef NV_CORE_UTILS_H
|
||||||
#define NV_CORE_UTILS_H
|
#define NV_CORE_UTILS_H
|
||||||
|
|
||||||
#include "nvcore.h"
|
|
||||||
#include "Debug.h" // nvDebugCheck
|
#include "Debug.h" // nvDebugCheck
|
||||||
|
|
||||||
|
#include <new> // for placement new
|
||||||
|
|
||||||
|
|
||||||
// Just in case. Grrr.
|
// Just in case. Grrr.
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
|
@ -24,6 +26,10 @@
|
||||||
#define NV_INT64_MIN (-POSH_I64(9223372036854775808))
|
#define NV_INT64_MIN (-POSH_I64(9223372036854775808))
|
||||||
#define NV_UINT64_MAX POSH_U64(0xffffffffffffffff)
|
#define NV_UINT64_MAX POSH_U64(0xffffffffffffffff)
|
||||||
|
|
||||||
|
#define NV_HALF_MAX 65504.0F
|
||||||
|
#define NV_FLOAT_MAX 3.402823466e+38F
|
||||||
|
|
||||||
|
|
||||||
namespace nv
|
namespace nv
|
||||||
{
|
{
|
||||||
// Less error prone than casting. From CB:
|
// Less error prone than casting. From CB:
|
||||||
|
@ -172,59 +178,6 @@ namespace nv
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline uint sdbmHash(const void * data_in, uint size, uint h = 5381)
|
|
||||||
{
|
|
||||||
const uint8 * data = (const uint8 *) data_in;
|
|
||||||
uint i = 0;
|
|
||||||
while (i < size) {
|
|
||||||
h = (h << 16) + (h << 6) - h + (uint) data[i++];
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note that this hash does not handle NaN properly.
|
|
||||||
inline uint sdbmFloatHash(const float * f, uint count, uint h = 5381)
|
|
||||||
{
|
|
||||||
for (uint i = 0; i < count; i++) {
|
|
||||||
//nvDebugCheck(nv::isFinite(*f));
|
|
||||||
union { float f; uint32 i; } x = { *f };
|
|
||||||
if (x.i == 0x80000000) x.i = 0;
|
|
||||||
h = sdbmHash(&x, 4, h);
|
|
||||||
}
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Some hash functors:
|
|
||||||
template <typename Key> struct Hash
|
|
||||||
{
|
|
||||||
uint operator()(const Key & k) const {
|
|
||||||
return sdbmHash(&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 <> struct Hash<float>
|
|
||||||
{
|
|
||||||
uint operator()(float f) const {
|
|
||||||
return sdbmFloatHash(&f, 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Key> struct Equal
|
|
||||||
{
|
|
||||||
bool operator()(const Key & k0, const Key & k1) const {
|
|
||||||
return k0 == k1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// @@ Move this to utils?
|
// @@ Move this to utils?
|
||||||
/// Delete all the elements of a container.
|
/// Delete all the elements of a container.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user