556 lines
13 KiB
C++
556 lines
13 KiB
C++
#ifndef __TARRAY_H__
|
|
#define __TARRAY_H__
|
|
|
|
#include "platform.h"
|
|
#if defined(LINUX)
|
|
#include "ILog.h"
|
|
#else
|
|
#include <assert.h>
|
|
#endif
|
|
|
|
#ifndef CLAMP
|
|
#define CLAMP(X, mn, mx) (X<mn ? mn : X<mx ? X : mx)
|
|
#endif
|
|
|
|
#ifndef LERP
|
|
#define LERP(A, B, Alpha) (A + Alpha * (B-A))
|
|
#endif
|
|
|
|
// Safe memory freeing
|
|
#ifndef SAFE_DELETE
|
|
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
|
|
#endif
|
|
|
|
#ifndef SAFE_DELETE_ARRAY
|
|
#define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p); (p)=NULL; } }
|
|
#endif
|
|
|
|
#ifndef SAFE_RELEASE
|
|
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
|
|
#endif
|
|
|
|
#ifndef SAFE_RELEASE_FORCE
|
|
#define SAFE_RELEASE_FORCE(p) { if(p) { (p)->Release(1); (p)=NULL; } }
|
|
#endif
|
|
|
|
// this is an allocator that's allocates 16-byte-aligned blocks,
|
|
// using the normal mem manager. The overhead of allocation is always 16 byte more,
|
|
// to keep the original address in the DWORD before the aligned address
|
|
// NOTE: since this is like a garbage collector (the items are not guaranteed to be
|
|
// freed immediately), the destructors won't be called
|
|
// for simplicity, constructors won't be called either
|
|
//
|
|
// DOES NOT construct / destruct objects, so use with care!
|
|
template <typename T>
|
|
class TAllocator16
|
|
{
|
|
public:
|
|
typedef size_t size_type;
|
|
typedef T *pointer;
|
|
|
|
TAllocator16 ()
|
|
#if defined(_DEBUG) && defined(_INC_CRTDBG) && !defined(WIN64)
|
|
: m_szParentObject("TAllocator16"),
|
|
m_nParentIndex (1)
|
|
#endif
|
|
{
|
|
}
|
|
TAllocator16 (const char* szParentObject, int nParentIndex)
|
|
#if defined(_DEBUG) && defined(_INC_CRTDBG) && !defined(WIN64)
|
|
: m_szParentObject(szParentObject),
|
|
m_nParentIndex (nParentIndex)
|
|
#endif
|
|
{
|
|
}
|
|
|
|
// allocates the aligned memory for the given number of objects;
|
|
// puts the pointer to the actually allocated block before the aligned memory block
|
|
pointer allocate (size_type _Count)
|
|
{
|
|
pointer p;
|
|
#if defined(_DEBUG) && defined(_INC_CRTDBG) && !defined(WIN64)
|
|
p = (pointer)_malloc_dbg (0x10+_Count * sizeof(T), _NORMAL_BLOCK, m_szParentObject, m_nParentIndex);
|
|
#else
|
|
p = (pointer)malloc (0x10+_Count*sizeof(T));
|
|
#endif
|
|
pointer pResult = (pointer)(((UINT_PTR)p+0x10)&~0xF);
|
|
// save the offset to the actual allocated address behind the useable aligned address
|
|
reinterpret_cast<int*>(pResult)[-1] = (char*)p - (char*)pResult;
|
|
return pResult;
|
|
}
|
|
|
|
pointer allocate_construct (size_type _Count)
|
|
{
|
|
pointer p = allocate(_Count);
|
|
return p;
|
|
}
|
|
|
|
void deallocate_destroy(pointer _Ptr)
|
|
{
|
|
if (!_Ptr)
|
|
return;
|
|
int nOffset = ((int*)_Ptr)[-1];
|
|
assert (nOffset >= -16 && nOffset <= -4);
|
|
#if defined(_DEBUG) && defined(_INC_CRTDBG) && !defined(WIN64)
|
|
_free_dbg (((char*)_Ptr)+nOffset, _NORMAL_BLOCK);
|
|
#else
|
|
free (((char*)_Ptr)+nOffset);
|
|
#endif
|
|
}
|
|
|
|
protected:
|
|
#if defined(_DEBUG) && defined(_INC_CRTDBG) && !defined(WIN64)
|
|
// the parent object (on behalf of which to call the new operator)
|
|
const char* m_szParentObject; // the file name
|
|
int m_nParentIndex; // the file line number
|
|
#endif
|
|
};
|
|
|
|
|
|
/*----------------------------------------------------------------------------
|
|
Sorting template.
|
|
----------------------------------------------------------------------------*/
|
|
|
|
//
|
|
// Sort elements. The sort is unstable, meaning that the ordering of equal
|
|
// items is not necessarily preserved.
|
|
//
|
|
template<class T> struct TSortStack
|
|
{
|
|
T* Min;
|
|
T* Max;
|
|
};
|
|
|
|
template<class T> void Sort( T* First, int Num )
|
|
{
|
|
if( Num<2 )
|
|
return;
|
|
TSortStack<T> RecursionStack[32]={{First,First+Num-1}}, Current, Inner;
|
|
for( TSortStack<T>* StackTop=RecursionStack; StackTop>=RecursionStack; --StackTop )
|
|
{
|
|
Current = *StackTop;
|
|
Loop:
|
|
INT Count = Current.Max - Current.Min + 1;
|
|
if( Count <= 8 )
|
|
{
|
|
// Use simple bubble-sort.
|
|
while( Current.Max > Current.Min )
|
|
{
|
|
T *Max, *Item;
|
|
for( Max=Current.Min, Item=Current.Min+1; Item<=Current.Max; Item++ )
|
|
if( Compare(*Item, *Max) > 0 )
|
|
Max = Item;
|
|
Exchange( *Max, *Current.Max-- );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Grab middle element so sort doesn't exhibit worst-cast behaviour with presorted lists.
|
|
Exchange( Current.Min[Count/2], Current.Min[0] );
|
|
|
|
// Divide list into two halves, one with items <=Current.Min, the other with items >Current.Max.
|
|
Inner.Min = Current.Min;
|
|
Inner.Max = Current.Max+1;
|
|
for( ; ; )
|
|
{
|
|
while( ++Inner.Min<=Current.Max && Compare(*Inner.Min, *Current.Min) <= 0 );
|
|
while( --Inner.Max> Current.Min && Compare(*Inner.Max, *Current.Min) >= 0 );
|
|
if( Inner.Min>Inner.Max )
|
|
break;
|
|
Exchange( *Inner.Min, *Inner.Max );
|
|
}
|
|
Exchange( *Current.Min, *Inner.Max );
|
|
|
|
// Save big half and recurse with small half.
|
|
if( Inner.Max-1-Current.Min >= Current.Max-Inner.Min )
|
|
{
|
|
if( Current.Min+1 < Inner.Max )
|
|
{
|
|
StackTop->Min = Current.Min;
|
|
StackTop->Max = Inner.Max - 1;
|
|
StackTop++;
|
|
}
|
|
if( Current.Max>Inner.Min )
|
|
{
|
|
Current.Min = Inner.Min;
|
|
goto Loop;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( Current.Max>Inner.Min )
|
|
{
|
|
StackTop->Min = Inner .Min;
|
|
StackTop->Max = Current.Max;
|
|
StackTop++;
|
|
}
|
|
if( Current.Min+1<Inner.Max )
|
|
{
|
|
Current.Max = Inner.Max - 1;
|
|
goto Loop;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
template<class T> class TArray
|
|
{
|
|
protected:
|
|
T* m_pElements;
|
|
int m_nCount;
|
|
int m_nAllocatedCount;
|
|
|
|
public:
|
|
typedef T value_type;
|
|
|
|
TArray(void) { m_pElements = NULL, m_nCount = m_nAllocatedCount = 0; }
|
|
TArray(int Count) { m_pElements = NULL; m_nCount = Count; m_nAllocatedCount = Count; Realloc(); }
|
|
TArray(int Use, int Max) { m_nCount = Use; m_nAllocatedCount = Max; Realloc(); }
|
|
~TArray(void)
|
|
{
|
|
Free();
|
|
}
|
|
|
|
void Reset(){Free();}
|
|
|
|
void Free()
|
|
{
|
|
if (m_pElements)
|
|
{
|
|
free(m_pElements);
|
|
m_pElements = NULL;
|
|
}
|
|
m_nCount = m_nAllocatedCount = 0;
|
|
}
|
|
|
|
void Create (int Count) { m_pElements = NULL; m_nCount = Count; m_nAllocatedCount = Count; Realloc(); Clear(); }
|
|
void Copy (const TArray<T>& src)
|
|
{
|
|
m_pElements = NULL;
|
|
m_nCount = m_nAllocatedCount = src.Num();
|
|
Realloc();
|
|
memcpy(m_pElements, src.m_pElements, src.Num()*sizeof(T));
|
|
}
|
|
void Copy (const T *src, int numElems)
|
|
{
|
|
for (int i=0; i<numElems; i++)
|
|
{
|
|
AddElem(src[i]);
|
|
}
|
|
}
|
|
#ifdef _XBOX
|
|
#ifndef _DEBUG
|
|
#ifndef realloc
|
|
#error !!!!!
|
|
#endif
|
|
#endif //_DEBUG
|
|
#endif //_XBOX
|
|
void Realloc()
|
|
{
|
|
m_pElements = (T *)realloc(m_pElements, m_nAllocatedCount*sizeof(T));
|
|
if (m_nAllocatedCount*sizeof(T))
|
|
assert (m_pElements);
|
|
}
|
|
|
|
void Remove(int Index,int Count=1)
|
|
{
|
|
if ( Count )
|
|
{
|
|
memcpy(m_pElements+Index, m_pElements+(Index+Count), sizeof(T)*(m_nCount-Index-Count));
|
|
m_nCount -= Count;
|
|
}
|
|
}
|
|
|
|
void Shrink()
|
|
{
|
|
if (m_nCount <= 0)
|
|
return;
|
|
assert(m_nAllocatedCount>=m_nCount);
|
|
if( m_nAllocatedCount != m_nCount )
|
|
{
|
|
m_nAllocatedCount = m_nCount;
|
|
Realloc();
|
|
}
|
|
}
|
|
|
|
void _Remove(int Index,int Count)
|
|
{
|
|
assert ( Index>=0 );
|
|
assert ( Index<=m_nCount );
|
|
assert ( (Index+Count)<=m_nCount );
|
|
|
|
Remove(Index, Count);
|
|
}
|
|
|
|
int Num(void) const { return m_nCount; }
|
|
int GetSize(void) const { return m_nAllocatedCount; }
|
|
void SetNum(int n) { m_nCount = m_nAllocatedCount = n; }
|
|
void SetUse(int n) { m_nCount = n; }
|
|
void Alloc(int n) { m_nAllocatedCount = n; Realloc(); }
|
|
void Reserve(int n) { SetNum(n); Realloc(); Clear(); }
|
|
void Expand(int n)
|
|
{
|
|
if (n > m_nAllocatedCount)
|
|
ReserveNew(n);
|
|
}
|
|
void ReserveNew(int n)
|
|
{
|
|
int num = m_nCount;
|
|
SetNum(n);
|
|
Realloc();
|
|
memset(&m_pElements[num], 0, sizeof(T)*(m_nCount-num));
|
|
}
|
|
void Grow(int n)
|
|
{
|
|
n += m_nCount;
|
|
SetNum(n);
|
|
Realloc();
|
|
}
|
|
void GrowReset(int n)
|
|
{
|
|
int num = m_nAllocatedCount;
|
|
AddIndex(n);
|
|
if (num != m_nAllocatedCount)
|
|
memset(&m_pElements[num], 0, sizeof(T)*(m_nAllocatedCount-num));
|
|
}
|
|
|
|
int *GetNumAddr(void) { return &m_nCount; }
|
|
T** GetDataAddr(void) { return &m_pElements; }
|
|
|
|
T* Data(void) const { return m_pElements; }
|
|
T& Get(int id) const { return m_pElements[id]; }
|
|
|
|
TArray& operator=(TArray& fa)
|
|
{
|
|
m_pElements = fa.m_pElements;
|
|
m_nCount = fa.m_nCount;
|
|
m_nAllocatedCount = fa.m_nAllocatedCount;
|
|
return *this;
|
|
}
|
|
|
|
/*const TArray operator=(TArray fa) const
|
|
{
|
|
TArray<T> t = TArray(fa.m_nCount,fa.m_nAllocatedCount);
|
|
for ( int i=0; i<fa.Num(); i++ )
|
|
{
|
|
t.AddElem(fa[i]);
|
|
}
|
|
return t;
|
|
}*/
|
|
|
|
const T& operator[](int i) const { return m_pElements[i]; }
|
|
T& operator[](int i) { return m_pElements[i]; }
|
|
T& operator * () { return *m_pElements; }
|
|
|
|
TArray(const TArray<T>& cTA)
|
|
{
|
|
m_pElements = NULL;
|
|
m_nCount = m_nAllocatedCount = cTA.Num();
|
|
Realloc();
|
|
m_nCount = 0;
|
|
for ( int i=0; i<cTA.Num(); i++ )
|
|
{
|
|
AddElem(cTA[i]);
|
|
}
|
|
}
|
|
|
|
void Clear(void)
|
|
{
|
|
memset(m_pElements, 0, m_nCount*sizeof(T));
|
|
}
|
|
|
|
void Set(int m)
|
|
{
|
|
memset(m_pElements, m, m_nAllocatedCount*sizeof(T));
|
|
}
|
|
|
|
void AddIndex(int inc)
|
|
{
|
|
m_nCount += inc;
|
|
if ( m_nCount > m_nAllocatedCount )
|
|
{
|
|
#ifdef PS2
|
|
m_nAllocatedCount = m_nCount + (m_nCount>>1) + 128;
|
|
#else
|
|
m_nAllocatedCount = m_nCount + (m_nCount>>1) + 32;
|
|
#endif
|
|
Realloc();
|
|
}
|
|
}
|
|
|
|
void AddIndexNoCache(int inc)
|
|
{
|
|
m_nCount += inc;
|
|
if ( m_nCount > m_nAllocatedCount )
|
|
{
|
|
m_nAllocatedCount = m_nCount;
|
|
Realloc();
|
|
}
|
|
}
|
|
|
|
void Add(const T & elem){AddElem(elem);}
|
|
void AddElem(const T elem)
|
|
{
|
|
int m = m_nCount;
|
|
AddIndex(1);
|
|
m_pElements[m] = elem;
|
|
}
|
|
void AddElemNoCache(const T elem)
|
|
{
|
|
int m = m_nCount;
|
|
AddIndexNoCache(1);
|
|
m_pElements[m] = elem;
|
|
}
|
|
|
|
int Find(const T & p)
|
|
{
|
|
for(int i=0; i<m_nCount; i++)
|
|
{
|
|
if(p == (*this)[i])
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void Delete(int n){DelElem(n);}
|
|
void DelElem(int n)
|
|
{
|
|
// memset(&m_pElements[n],0,sizeof(T));
|
|
_Remove(n, 1);
|
|
}
|
|
|
|
void Load(const char * file_name)
|
|
{
|
|
Clear();
|
|
FILE * f = fxopen(file_name, "rb");
|
|
if(!f)
|
|
return;
|
|
|
|
int size = 0;
|
|
fread(&size, 4, 1, f);
|
|
|
|
while(!feof(f) && sizeof(T)==size)
|
|
{
|
|
T tmp;
|
|
if(fread(&tmp, 1, sizeof(T), f) == sizeof(T))
|
|
AddElem(tmp);
|
|
}
|
|
|
|
fclose(f);
|
|
}
|
|
|
|
|
|
/* LINUX - port [MG], this is not needed and does not compile with gcc under linux
|
|
// Sorting
|
|
static int Cmp_Ptrs1(const void* v1, const void* v2)
|
|
{
|
|
T* p1 = (T*)v1;
|
|
T* p2 = (T*)v2;
|
|
|
|
if(p1->distance > p2->distance)
|
|
return 1;
|
|
else if(p1->distance < p2->distance)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Cmp_Ptrs2(const void* v1, const void* v2)
|
|
{
|
|
T* p1 = (T*)v1;
|
|
T* p2 = (T*)v2;
|
|
|
|
if(p1->distance > p2->distance)
|
|
return -1;
|
|
else if(p1->distance < p2->distance)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void SortByDistanceMember(bool front_to_back = true)
|
|
{
|
|
if(front_to_back)
|
|
qsort(&m_pElements[0], m_nCount, sizeof(T), Cmp_Ptrs1);
|
|
else
|
|
qsort(&m_pElements[0], m_nCount, sizeof(T), Cmp_Ptrs2);
|
|
}
|
|
*/
|
|
|
|
// Save/Load
|
|
void SaveToBuffer(const unsigned char * pBuffer, int & nPos)
|
|
{
|
|
// copy size of element
|
|
int nSize = sizeof(T);
|
|
if(pBuffer)
|
|
memcpy((void*)&pBuffer[nPos],&nSize,4);
|
|
nPos+=4;
|
|
|
|
// copy count
|
|
if(pBuffer)
|
|
memcpy((void*)&pBuffer[nPos],&m_nCount,4);
|
|
nPos+=4;
|
|
|
|
// copy data
|
|
if(m_nCount)
|
|
{
|
|
if(pBuffer)
|
|
memcpy((void*)&pBuffer[nPos], m_pElements, sizeof(T)*m_nCount);
|
|
nPos += sizeof(T)*m_nCount;
|
|
}
|
|
}
|
|
|
|
void LoadFromBuffer(const unsigned char * pBuffer, int & nPos)
|
|
{
|
|
Reset();
|
|
|
|
// copy size of element
|
|
int nElemSize = 0;
|
|
memcpy(&nElemSize,(void*)&pBuffer[nPos],4);
|
|
assert(nElemSize == sizeof(T));
|
|
nPos+=4;
|
|
|
|
// copy count
|
|
int nNewCount=0;
|
|
memcpy((void*)&nNewCount,&pBuffer[nPos],4);
|
|
assert(nNewCount>=0 && nNewCount<1000000);
|
|
nPos+=4;
|
|
|
|
// copy data
|
|
if(nNewCount)
|
|
{
|
|
Reserve(nNewCount);
|
|
memcpy((void*)m_pElements, &pBuffer[nPos], sizeof(T)*nNewCount);
|
|
nPos += sizeof(T)*nNewCount;
|
|
}
|
|
}
|
|
|
|
// Standard compliance interface
|
|
//
|
|
// This is for those who don't want to learn the non standard and
|
|
// thus not very convenient interface of TArray, but are unlucky
|
|
// enough not to be able to avoid using it.
|
|
void clear(){Free();}
|
|
unsigned size()const {return m_nCount;}
|
|
unsigned capacity() const {return m_nAllocatedCount;}
|
|
bool empty()const {return size() == 0;}
|
|
void push_back (const T& rSample) {Add(rSample);}
|
|
T* begin() {return m_pElements;}
|
|
T* end() {return m_pElements + m_nCount;}
|
|
const T* begin()const {return m_pElements;}
|
|
const T* end()const {return m_pElements + m_nCount;}
|
|
|
|
int GetMemoryUsage() { return (int)(m_nAllocatedCount*sizeof(T)); }
|
|
};
|
|
|
|
template <class T> inline void Exchange(T& X, T& Y)
|
|
{
|
|
const T Tmp = X;
|
|
X = Y;
|
|
Y = Tmp;
|
|
}
|
|
|
|
#endif // __TARRAY_H__
|