You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1253 lines
31 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef hsTemplatesDefined
#define hsTemplatesDefined
#include "hsExceptions.h"
#include "hsMemory.h"
#include "hsRefCnt.h"
#include "hsUtils.h"
#include <stdarg.h>
#ifdef HS_DEBUGGING
// #define HS_DEBUGTARRAY
#endif
#ifdef HS_DEBUGTARRAY
// just a quickie d-link list class for debugging
class hsDlistNode
{
public:
static hsDlistNode *fpFirst;
static hsDlistNode *fpLast;
static UInt32 fcreated;
static UInt32 fdestroyed;
void *fpThing;
hsDlistNode *fpPrev;
hsDlistNode *fpNext;
hsDlistNode(void *tng): fpThing(tng), fpNext(0), fpPrev(0) { AddNode(); }
void AddNode();
void RemoveNode();
hsDlistNode *GetNext() { return fpNext; }
};
#endif
// Use this for a pointer to a single object of class T allocated with new
template <class T> class hsTempObject {
T* fObject;
public:
hsTempObject(): fObject(nil){}
hsTempObject(T* p) : fObject(p) {}
hsTempObject(const hsTempObject & that)
{*this=that;}
~hsTempObject() { delete fObject; }
hsTempObject & operator=(const hsTempObject & src)
{
if (fObject!=src.fObject)
{
delete fObject;
fObject=src.fObject;
}
return *this;
}
hsTempObject & operator=(T * ptr)
{
if (fObject!=ptr)
{
delete fObject;
fObject=ptr;
}
return *this;
}
operator T*() const { return fObject; }
operator T*&() { return fObject; }
operator const T&() const { return *fObject; }
operator bool() const { return fObject!=nil;}
T * operator->() const { return fObject; }
T * operator *() const { return fObject; }
};
// Use this for subclasses of hsRefCnt, where UnRef should be called at the end
template <class T> class hsTempRef {
T* fObject;
public:
hsTempRef(T* object = nil) : fObject(object) {}
~hsTempRef() { if (fObject) fObject->UnRef(); }
operator T*() const { return fObject; }
T* operator->() const { return fObject; }
T* operator=(T* src) { hsRefCnt_SafeUnRef(fObject); fObject = src; return fObject; }
};
// Use this for an array of objects of class T allocated with new[]
template <class T> class hsTempArray {
T* fArray;
UInt32 fCount;
hsTempArray<T>& operator=(const hsTempArray<T>&);
public:
hsTempArray(long count) : fArray(TRACKED_NEW T[count]), fCount(count)
{
}
hsTempArray(long count, T initValue) : fArray(TRACKED_NEW T[count]), fCount(count)
{
for (int i = 0; i < count; i++)
fArray[i] = initValue;
}
hsTempArray(T* p) : fArray(p), fCount(1)
{
}
hsTempArray() : fArray(nil), fCount(0)
{
}
~hsTempArray()
{
delete[] fArray;
}
operator T*() const { return fArray; }
T* GetArray() const { return fArray; }
void Accomodate(UInt32 count)
{
if (count > fCount)
{ delete[] fArray;
fCount = count;
fArray = TRACKED_NEW T[count];
}
}
};
////////////////////////////////////////////////////////////////////////////////
//
//// Like hsTempArray, but more useful when working with char * type arrays.
//enum KStringFormatConstructor {kFmtCtor};
//enum KStringFormatVConstructor {kFmtVCtor};
//class hsTempString
//{
//public:
// char * fStr;
// hsTempString(): fStr(nil){}
// hsTempString(char * p) : fStr(p) {}
// hsTempString(const char * p) { fStr=hsStrcpy(p); }
// hsTempString(KStringFormatConstructor, char * fmt, ...);
// hsTempString(KStringFormatVConstructor, char * fmt, va_list args);
// hsTempString(const hsTempString & other):fStr(hsStrcpy(other.fStr)){}
// virtual ~hsTempString() { delete [] fStr; }
// hsTempString & operator=(char * ptr)
// {
// if (fStr!=ptr)
// {
// delete [] fStr;
// fStr=ptr;
// }
// return *this;
// }
// hsTempString & operator=(const hsTempString & other)
// {
// delete [] fStr;
// fStr=hsStrcpy(other.fStr);
// return *this;
// }
// operator char *() const { return fStr; }
// operator char *&() { return fStr; }
// operator const char *() const { return fStr; }
// operator bool() const { return fStr!=nil;}
// char * operator *() const { return fStr; }
// const char* c_str() const { return fStr; }
// char* c_str() { return fStr; }
//};
//
//// shorthand
//typedef hsTempString tmpstr_t;
//
//class hsTempStringF : public hsTempString
//{
//public:
// hsTempStringF(char * fmt, ...);
// void Format(char * fmt, ...);
//
// hsTempString & operator=(char * ptr) { return hsTempString::operator=(ptr); }
// hsTempString & operator=(const hsTempString & other) { return hsTempString::operator=(other); }
// hsTempString & operator=(const hsTempStringF & other) { return hsTempString::operator=(other); }
// operator char *() const { return fStr; }
// operator char *&() { return fStr; }
// operator const char *() const { return fStr; }
// operator bool() const { return fStr!=nil;}
// char * operator *() const { return fStr; }
//};
//////////////////////////////////////////////////////////////////////////////
template <class T> class hsDynamicArray {
private:
Int32 fCount;
T* fArray;
hsDynamicArray<T>& operator=(const hsDynamicArray<T>&); // don't allow assignment
public:
enum { kMissingIndex = -1 };
hsDynamicArray(Int32 count = 0);
virtual ~hsDynamicArray();
Int32 GetCount() const { return fCount; }
hsBool IsEmpty() const { return fCount == 0; }
const T& Get(Int32 index) const;
Int32 Get(Int32 index, Int32 count, T data[]) const;
Int32 Find(const T&) const; // returns kMissingIndex if not found
void SetCount(Int32 count);
T& operator[]( Int32 index );
Int32 Append(const T&);
Int32 InsertAtIndex(UInt32 index, const T& obj);
Int32 Push(const T&);
Int32 Pop(T*);
void Remove(Int32);
void Reset(); // clears out everything
T* AcquireArray() { return fArray; }
T* DetachArray() { T* t = fArray; fCount = 0; fArray = nil; return t; }
void ReleaseArray(T*) {}
hsDynamicArray<T>* Copy(hsDynamicArray<T>* dst = nil) const;
T* ForEach(Boolean (*proc)(T&));
T* ForEach(Boolean (*proc)(T&, void* p1), void* p1);
T* ForEach(Boolean (*proc)(T&, void* p1, void* p2), void* p1, void* p2);
};
// Use this for block of memory allocated with HSMemory::New()
template <class T> class hsDynamicArrayAccess {
T* fArray;
hsDynamicArray<T> *fArrayObj;
hsDynamicArrayAccess<T>& operator=(const hsDynamicArrayAccess<T>&);
public:
hsDynamicArrayAccess(hsDynamicArray<T> *array) : fArrayObj(array) { fArray = array->AcquireArray();}
~hsDynamicArrayAccess() { fArrayObj->ReleaseArray(fArray); }
operator T*() const { return fArray; }
T* operator->() const { return fArray; }
};
template <class T>
hsDynamicArray<T>::hsDynamicArray(Int32 count)
{
fCount = count;
fArray = nil;
if (count)
fArray = TRACKED_NEW T[ count ];
}
template <class T>
hsDynamicArray<T>::~hsDynamicArray()
{
this->Reset();
}
template <class T>
void hsDynamicArray<T>::SetCount(Int32 count)
{
if (fCount != count)
{ if (count == 0)
this->Reset();
else
{ T* newArray = TRACKED_NEW T[count];
if (fArray)
{ int copyCount = hsMinimum(count, fCount);
for (int i = 0; i < copyCount; i++)
newArray[i] = fArray[i];
delete[] fArray;
}
fCount = count;
fArray = newArray;
}
}
}
template <class T> T& hsDynamicArray<T>::operator[]( Int32 index )
{
hsDebugCode(hsThrowIfBadParam((UInt32)index >= (UInt32)fCount);)
return fArray[index];
}
template <class T> const T& hsDynamicArray<T>::Get( Int32 index ) const
{
hsDebugCode(hsThrowIfBadParam((UInt32)index >= (UInt32)fCount);)
return fArray[index];
}
template <class T>
Int32 hsDynamicArray<T>::Get(Int32 index, Int32 count, T data[]) const
{
if (count > 0)
{ hsThrowIfNilParam(data);
hsThrowIfBadParam((UInt32)index >= fCount);
if (index + count > fCount)
count = fCount - index;
for (int i = 0; i < count; i++)
data[i] = fArray[i + index];
}
return count;
}
template <class T>
Int32 hsDynamicArray<T>::Find(const T& obj) const
{
for (int i = 0; i < fCount; i++)
if (fArray[i] == obj)
return i;
return kMissingIndex;
}
template <class T>
void hsDynamicArray<T>::Remove(Int32 index)
{
hsThrowIfBadParam((UInt32)index >= (UInt32)fCount);
T rVal = fArray[index];
if (--fCount > 0)
{
int i;
T* newList = TRACKED_NEW T[fCount];
for(i = 0 ; i < index;i++)
newList[i] = fArray[i];
for (i = index; i < fCount; i++)
newList[i] = fArray[i + 1];
delete [] fArray;
fArray = newList;
}
else
{ delete[] fArray;
fArray = nil;
}
}
template <class T>
Int32 hsDynamicArray<T>::Pop(T *obj)
{
hsThrowIfBadParam(this->IsEmpty());
*obj = fArray[0];
Remove(0);
return fCount;
}
template <class T>
Int32 hsDynamicArray<T>::Push(const T& obj)
{
if (fArray)
{
T* newList = TRACKED_NEW T[fCount+1];
for(int i = 0 ; i < fCount; i++)
newList[i+1] = fArray[i];
newList[0] = obj;
delete [] fArray;
fArray = newList;
}
else
{ hsAssert(fCount == 0, "mismatch");
fArray = TRACKED_NEW T[1];
fArray[0] = obj;
}
return ++fCount;
}
template <class T>
Int32 hsDynamicArray<T>::Append(const T& obj)
{
if (fArray)
{ T* newList = TRACKED_NEW T[fCount + 1];
for (int i = 0; i < fCount; i++)
newList[i] = fArray[i];
newList[fCount] = obj;
delete [] fArray;
fArray = newList;
}
else
{ hsAssert(fCount == 0, "mismatch");
fArray = TRACKED_NEW T[1];
fArray[0] = obj;
}
return ++fCount;
}
template <class T>
Int32 hsDynamicArray<T>::InsertAtIndex(UInt32 index, const T& obj)
{
if (fArray)
{
hsAssert(UInt32(fCount) >= index, "Index too large for array");
T* newList = TRACKED_NEW T[fCount + 1];
unsigned i;
for ( i = 0; i < index; i++)
newList[i] = fArray[i];
newList[index] = obj;
for ( i = index; i < UInt32(fCount); i++)
newList[i+1] = fArray[i];
delete [] fArray;
fArray = newList;
}
else
{
hsAssert(fCount == 0, "mismatch");
hsAssert(index ==0,"Can't insert at non zero index in empty array");
fArray = TRACKED_NEW T[1];
fArray[0] = obj;
}
return ++fCount;
}
template <class T> void hsDynamicArray<T>::Reset()
{
if (fArray)
{ delete[] fArray;
fArray = nil;
fCount = 0;
}
}
template <class T>
hsDynamicArray<T>* hsDynamicArray<T>::Copy(hsDynamicArray<T>* dst) const
{
if (dst == nil)
dst = TRACKED_NEW hsDynamicArray<T>;
else
dst->Reset();
dst->SetCount(this->fCount);
for (int i = 0; i < this->fCount; i++)
dst->fArray[i] = this->fArray[i];
return dst;
}
template <class T> T* hsDynamicArray<T>::ForEach(Boolean (*proc)(T&))
{
for (int i = 0; i < fCount; i++)
if (proc(fArray[i]))
return &fArray[i];
return nil;
}
template <class T> T* hsDynamicArray<T>::ForEach(Boolean (*proc)(T&, void* p1), void * p1)
{
for (int i = 0; i < fCount; i++)
if (proc(fArray[i], p1))
return &fArray[i];
return nil;
}
template <class T> T* hsDynamicArray<T>::ForEach(Boolean (*proc)(T&, void* p1, void* p2), void *p1, void *p2)
{
for (int i = 0; i < fCount; i++)
if (proc(fArray[i], p1, p2))
return &fArray[i];
return nil;
}
////////////////////////////////////////////////////////////////////////////////
class hsTArrayBase
{
protected:
UInt16 fUseCount;
UInt16 fTotalCount;
void GrowArraySize(UInt16 nSize);
#ifdef HS_DEBUGTARRAY
hsTArrayBase();
virtual char *GetTypeName();
virtual int GetSizeOf();
hsDlistNode *self;
friend void TArrayStats();
virtual ~hsTArrayBase();
#else
hsTArrayBase():fUseCount(0), fTotalCount(0){}
#endif
public:
UInt16 GetNumAlloc() const { return fTotalCount; }
};
template <class T> class hsTArray : public hsTArrayBase
{
T* fArray;
inline void IncCount(int index, int count);
inline void DecCount(int index, int count);
#ifdef HS_DEBUGGING
#define hsTArray_ValidateCount(count) hsAssert(((count) >= 0)&&((count) <= 0xffffL), "bad count")
#define hsTArray_ValidateIndex(index) hsAssert(unsigned(index) < fUseCount, "bad index")
#define hsTArray_ValidateInsertIndex(index) hsAssert(unsigned(index) <= fUseCount, "bad index")
#define hsTArray_Validate(condition) hsAssert(condition, "oops")
#ifdef HS_DEBUGTARRAY
virtual int GetSizeOf() { return sizeof(T); }
#endif
#else
#define hsTArray_ValidateCount(count)
#define hsTArray_ValidateIndex(index)
#define hsTArray_ValidateInsertIndex(index)
#define hsTArray_Validate(condition)
#endif
public:
hsTArray() : fArray(nil) {}
inline hsTArray(int count);
inline hsTArray(const hsTArray<T>& src);
~hsTArray() { if (fArray) delete[] fArray;
}
inline void Expand(int NewTotal);
inline hsTArray<T>& operator=(const hsTArray<T>& src);
bool operator==(const hsTArray<T>& src) const; // checks sizes and contents
// Swaps the internal data (including the fArray POINTER) with the data from the array given
void Swap( hsTArray<T>& src );
void Set(int index, const T& item) { hsTArray_ValidateIndex(index); fArray[index]=item; }
const T& Get(int index) const { hsTArray_ValidateIndex(index); return fArray[index]; }
T& operator[](int index) const { hsTArray_ValidateIndex(index); return fArray[index]; }
T* FirstIter() { return &fArray[0]; }
T* StopIter() { return &fArray[fUseCount]; }
int Count() const { return fUseCount; }
int GetCount() const { return fUseCount; }
inline void SetCount(int count);
inline void SetCountAndZero(int count); // does block clear, don't use for types with vtbl
inline void ExpandAndZero(int count); // Same as set count and zero except won't decrease
// usecount
inline void Reset();
T* Insert(int index)
{
hsTArray_ValidateInsertIndex(index);
this->IncCount(index, 1);
return &fArray[index];
}
void Insert(int index, const T& item)
{
hsTArray_ValidateInsertIndex(index);
this->IncCount(index, 1);
fArray[index] = item;
}
void Insert(int index, int count, T item[])
{
hsTArray_ValidateCount(count);
if (count > 0)
{ hsTArray_ValidateInsertIndex(index);
this->IncCount(index, count);
hsTArray_CopyForward(item, &fArray[index], count);
}
}
// This guy is a duplicate for compatibility with the older hsDynamicArray<>
void InsertAtIndex(int index, const T& item) { this->Insert(index, item); }
void Remove(int index)
{
hsTArray_ValidateIndex(index);
this->DecCount(index, 1);
}
void Remove(int index, int count)
{
hsTArray_ValidateCount(count);
hsTArray_ValidateIndex(index);
hsTArray_ValidateIndex(index + count - 1);
this->DecCount(index, count);
}
hsBool RemoveItem(const T& item);
T* Push()
{
this->IncCount(fUseCount, 1);
return &fArray[fUseCount - 1];
}
void Push(const T& item)
{
this->IncCount(fUseCount, 1);
fArray[fUseCount - 1] = item;
}
void Append(const T& item)
{
this->IncCount(fUseCount, 1);
fArray[fUseCount - 1] = item;
}
inline T Pop();
inline const T& Peek() const;
enum {
kMissingIndex = -1
};
int Find(const T& item) const; // returns kMissingIndex if not found
inline T* ForEach(hsBool (*proc)(T&));
inline T* ForEach(hsBool (*proc)(T&, void* p1), void* p1);
inline T* ForEach(hsBool (*proc)(T&, void* p1, void* p2), void* p1, void* p2);
T* DetachArray()
{
T* array = fArray;
fUseCount = fTotalCount = 0;
fArray = nil;
return array;
}
T* AcquireArray() { return fArray; }
};
////////////// Public hsTArray methods
template <class T> hsTArray<T>::hsTArray(int count) : fArray(nil)
{
hsTArray_ValidateCount(count);
fUseCount = fTotalCount = count;
if (count > 0)
fArray = TRACKED_NEW T[count];
}
template <class T> hsTArray<T>::hsTArray(const hsTArray<T>& src) : fArray(nil)
{
int count = src.Count();
fUseCount = fTotalCount = count;
if (count > 0)
{
fArray = TRACKED_NEW T[count];
hsTArray_CopyForward(src.fArray, fArray, count);
}
}
template <class T> hsTArray<T>& hsTArray<T>::operator=(const hsTArray<T>& src)
{
if (this->Count() != src.Count())
this->SetCount(src.Count());
hsTArray_CopyForward(src.fArray, fArray, src.Count());
return *this;
}
// checks sizes and contents
template <class T>
bool hsTArray<T>::operator==(const hsTArray<T>& src) const
{
if (&src==this)
return true; // it's me
if (GetCount() != src.GetCount())
return false; // different sizes
int i;
for(i=0;i<GetCount();i++)
if (Get(i) != src[i])
return false; // different contents
return true; // the same
}
//// Swap ////////////////////////////////////////////////////////////////////
// Added 5.2.2001 mcn - Given another hsTArray of the same type, "swaps" the
// data stored in both. Basically we're literally swapping the fArray pointers
// around, plus the use counts and such.
template <class T> void hsTArray<T>::Swap( hsTArray<T>& src )
{
UInt16 use, tot;
T *array;
use = fUseCount;
tot = fTotalCount;
array = fArray;
fUseCount = src.fUseCount;
fTotalCount = src.fTotalCount;
fArray = src.fArray;
src.fUseCount = use;
src.fTotalCount = tot;
src.fArray = array;
}
template <class T> void hsTArray<T>::SetCountAndZero(int count)
{
if( fTotalCount <= count )
{
int n = fTotalCount;
Expand(count);
}
int i;
for( i = 0; i < fTotalCount; i++ )
fArray[i] = nil;
fUseCount = count;
}
template <class T> void hsTArray<T>::ExpandAndZero(int count)
{
if( fTotalCount <= count )
{
int n = fTotalCount;
Expand(count);
int i;
for( i = n; i < count; i++ )
fArray[i] = nil;
}
if( fUseCount < count )
fUseCount = count;
}
template <class T> void hsTArray<T>::SetCount(int count)
{
hsTArray_ValidateCount(count);
if (count > fTotalCount)
{
if (fArray)
delete[] fArray;
fArray = TRACKED_NEW T[count];
fUseCount = fTotalCount = count;
}
fUseCount = count;
}
template <class T> void hsTArray<T>::Expand(int NewCount) // New Count is Absolute not additional
{
hsTArray_ValidateCount(NewCount);
if (NewCount > fTotalCount) // This is Expand not Shrink
{
T* newArray = TRACKED_NEW T[NewCount];
if (fArray != nil)
{ hsTArray_CopyForward(fArray, newArray, fUseCount);
// hsTArray_CopyForward(&fArray[index], &newArray[index + count], fUseCount - index);
delete[] fArray;
}
fArray = newArray;
fTotalCount = NewCount;
}
}
template <class T> void hsTArray<T>::Reset()
{
if (fArray)
{
delete[] fArray;
fArray = nil;
fUseCount = fTotalCount = 0;
}
}
template <class T> T hsTArray<T>::Pop()
{
hsTArray_Validate(fUseCount > 0);
fUseCount -= 1;
return fArray[fUseCount];
}
template <class T> const T& hsTArray<T>::Peek() const
{
hsTArray_Validate(fUseCount > 0);
return fArray[fUseCount-1];
}
template <class T> int hsTArray<T>::Find(const T& item) const
{
for (int i = 0; i < fUseCount; i++)
if (fArray[i] == item)
return i;
return kMissingIndex;
}
template <class T> hsBool hsTArray<T>::RemoveItem(const T& item)
{
for (int i = 0; i < fUseCount; i++)
if (fArray[i] == item)
{ this->DecCount(i, 1);
return true;
}
return false;
}
////////// These are the private methods for hsTArray
template <class T> void hsTArray_CopyForward(const T src[], T dst[], int count)
{
for (int i = 0; i < count; i++)
dst[i] = src[i];
}
template <class T> void hsTArray_CopyBackward(const T src[], T dst[], int count)
{
for (int i = count - 1; i >= 0; --i)
dst[i] = src[i];
}
template <class T> void hsTArray<T>::IncCount(int index, int count)
{
int newCount = fUseCount + count;
if (newCount > fTotalCount)
{ if (fTotalCount == 0)
fTotalCount = newCount;
GrowArraySize(newCount); // Sets new fTotalCount
T* newArray = TRACKED_NEW T[fTotalCount];
if (fArray != nil)
{ hsTArray_CopyForward(fArray, newArray, index);
hsTArray_CopyForward(&fArray[index], &newArray[index + count], fUseCount - index);
delete[] fArray;
}
fArray = newArray;
}
else
hsTArray_CopyBackward(&fArray[index], &fArray[index + count], fUseCount - index);
fUseCount = newCount;
}
template <class T> void hsTArray<T>::DecCount(int index, int count)
{
if (fUseCount == count)
this->Reset();
else
{ hsTArray_CopyForward(&fArray[index + count], &fArray[index], fUseCount - index - count);
fUseCount -= count;
}
}
template <class T> T* hsTArray<T>::ForEach(hsBool (*proc)(T&))
{
for (int i = 0; i < fUseCount; i++)
if (proc(fArray[i]))
return &fArray[i];
return nil;
}
template <class T> T* hsTArray<T>::ForEach(hsBool (*proc)(T&, void* p1), void* p1)
{
for (int i = 0; i < fUseCount; i++)
if (proc(fArray[i], p1))
return &fArray[i];
return nil;
}
template <class T> T* hsTArray<T>::ForEach(hsBool (*proc)(T&, void* p1, void* p2), void* p1, void* p2)
{
for (int i = 0; i < fUseCount; i++)
if (proc(fArray[i], p1, p2))
return &fArray[i];
return nil;
}
////////////////////////////////////////////////////////////////////////////////////////////////
//
// hsTArray's big brother. Only to be used when expecting more than 64K of elements. The
// only difference between hsTArray and hsLargeArray is LargeArray uses 32 bit counters,
// vs 16 bit counters for hsTArray.
class hsLargeArrayBase
{
protected:
UInt32 fUseCount;
UInt32 fTotalCount;
void GrowArraySize(UInt32 nSize);
#ifdef HS_DEBUGTARRAY
hsLargeArrayBase();
virtual char *GetTypeName();
virtual int GetSizeOf();
hsDlistNode *self;
friend void LargeArrayStats();
virtual ~hsLargeArrayBase();
#else
hsLargeArrayBase():fUseCount(0), fTotalCount(0){}
#endif
public:
UInt32 GetNumAlloc() const { return fTotalCount; }
};
template <class T> class hsLargeArray : public hsLargeArrayBase
{
T* fArray;
inline void IncCount(int index, int count);
inline void DecCount(int index, int count);
#ifdef HS_DEBUGGING
#define hsLargeArray_ValidateCount(count) hsAssert((count) >= 0, "bad count")
#define hsLargeArray_ValidateIndex(index) hsAssert(unsigned(index) < fUseCount, "bad index")
#define hsLargeArray_ValidateInsertIndex(index) hsAssert(unsigned(index) <= fUseCount, "bad index")
#define hsLargeArray_Validate(condition) hsAssert(condition, "oops")
#ifdef HS_DEBUGTARRAY
virtual int GetSizeOf() { return sizeof(T); }
#endif
#else
#define hsLargeArray_ValidateCount(count)
#define hsLargeArray_ValidateIndex(index)
#define hsLargeArray_ValidateInsertIndex(index)
#define hsLargeArray_Validate(condition)
#endif
public:
hsLargeArray() : fArray(nil) {}
inline hsLargeArray(int count);
inline hsLargeArray(const hsLargeArray<T>& src);
~hsLargeArray() { if (fArray) delete[] fArray;
}
inline void Expand(int NewTotal);
inline hsLargeArray<T>& operator=(const hsLargeArray<T>& src);
// Swaps the internal data (including the fArray POINTER) with the data from the array given
void Swap( hsLargeArray<T>& src );
void Set(int index, const T& item) { hsLargeArray_ValidateIndex(index); fArray[index]=item; }
const T& Get(int index) const { hsLargeArray_ValidateIndex(index); return fArray[index]; }
T& operator[](int index) const { hsLargeArray_ValidateIndex(index); return fArray[index]; }
T* FirstIter() { return &fArray[0]; }
T* StopIter() { return &fArray[fUseCount]; }
int Count() const { return fUseCount; }
int GetCount() const { return fUseCount; }
inline void SetCount(int count);
inline void SetCountAndZero(int count); // does block clear, don't use for types with vtbl
inline void ExpandAndZero(int count); // Same as set count and zero except won't decrease
// usecount
inline void Reset();
T* Insert(int index)
{
hsLargeArray_ValidateInsertIndex(index);
this->IncCount(index, 1);
return &fArray[index];
}
void Insert(int index, const T& item)
{
hsLargeArray_ValidateInsertIndex(index);
this->IncCount(index, 1);
fArray[index] = item;
}
void Insert(int index, int count, T item[])
{
hsLargeArray_ValidateCount(count);
if (count > 0)
{ hsLargeArray_ValidateInsertIndex(index);
this->IncCount(index, count);
hsLargeArray_CopyForward(item, &fArray[index], count);
}
}
// This guy is a duplicate for compatibility with the older hsDynamicArray<>
void InsertAtIndex(int index, const T& item) { this->Insert(index, item); }
void Remove(int index)
{
hsLargeArray_ValidateIndex(index);
this->DecCount(index, 1);
}
void Remove(int index, int count)
{
hsLargeArray_ValidateCount(count);
hsLargeArray_ValidateIndex(index);
hsLargeArray_ValidateIndex(index + count - 1);
this->DecCount(index, count);
}
hsBool RemoveItem(const T& item);
T* Push()
{
this->IncCount(fUseCount, 1);
return &fArray[fUseCount - 1];
}
void Push(const T& item)
{
this->IncCount(fUseCount, 1);
fArray[fUseCount - 1] = item;
}
void Append(const T& item)
{
this->IncCount(fUseCount, 1);
fArray[fUseCount - 1] = item;
}
inline T Pop();
inline const T& Peek() const;
enum {
kMissingIndex = -1
};
int Find(const T& item) const; // returns kMissingIndex if not found
inline T* ForEach(hsBool (*proc)(T&));
inline T* ForEach(hsBool (*proc)(T&, void* p1), void* p1);
inline T* ForEach(hsBool (*proc)(T&, void* p1, void* p2), void* p1, void* p2);
T* DetachArray()
{
T* array = fArray;
fUseCount = fTotalCount = 0;
fArray = nil;
return array;
}
T* AcquireArray() { return fArray; }
};
////////////// Public hsLargeArray methods
template <class T> hsLargeArray<T>::hsLargeArray(int count) : fArray(nil)
{
hsLargeArray_ValidateCount(count);
fUseCount = fTotalCount = count;
if (count > 0)
fArray = TRACKED_NEW T[count];
}
template <class T> hsLargeArray<T>::hsLargeArray(const hsLargeArray<T>& src) : fArray(nil)
{
int count = src.Count();
fUseCount = fTotalCount = count;
if (count > 0)
{
fArray = TRACKED_NEW T[count];
hsLargeArray_CopyForward(src.fArray, fArray, count);
}
}
template <class T> hsLargeArray<T>& hsLargeArray<T>::operator=(const hsLargeArray<T>& src)
{
if (this->Count() != src.Count())
this->SetCount(src.Count());
hsLargeArray_CopyForward(src.fArray, fArray, src.Count());
return *this;
}
template <class T> void hsLargeArray<T>::Swap( hsLargeArray<T>& src )
{
UInt32 use, tot;
T *array;
use = fUseCount;
tot = fTotalCount;
array = fArray;
fUseCount = src.fUseCount;
fTotalCount = src.fTotalCount;
fArray = src.fArray;
src.fUseCount = use;
src.fTotalCount = tot;
src.fArray = array;
}
template <class T> void hsLargeArray<T>::SetCountAndZero(int count)
{
if( fTotalCount <= count )
{
int n = fTotalCount;
Expand(count);
}
HSMemory::Clear(fArray, fTotalCount * sizeof( T ));
fUseCount = count;
}
template <class T> void hsLargeArray<T>::ExpandAndZero(int count)
{
if( fTotalCount <= count )
{
int n = fTotalCount;
Expand(count);
HSMemory::Clear(fArray+n, (count - n) * sizeof( T ));
}
if( fUseCount < count )
fUseCount = count;
}
template <class T> void hsLargeArray<T>::SetCount(int count)
{
hsLargeArray_ValidateCount(count);
if (count > fTotalCount)
{
if (fArray)
delete[] fArray;
fArray = TRACKED_NEW T[count];
fUseCount = fTotalCount = count;
}
fUseCount = count;
}
template <class T> void hsLargeArray<T>::Expand(int NewCount) // New Count is Absolute not additional
{
hsLargeArray_ValidateCount(NewCount);
if (NewCount > fTotalCount) // This is Expand not Shrink
{
T* newArray = TRACKED_NEW T[NewCount];
if (fArray != nil)
{ hsLargeArray_CopyForward(fArray, newArray, fUseCount);
// hsLargeArray_CopyForward(&fArray[index], &newArray[index + count], fUseCount - index);
delete[] fArray;
}
fArray = newArray;
fTotalCount = NewCount;
}
}
template <class T> void hsLargeArray<T>::Reset()
{
if (fArray)
{
delete[] fArray;
fArray = nil;
fUseCount = fTotalCount = 0;
}
}
template <class T> T hsLargeArray<T>::Pop()
{
hsLargeArray_Validate(fUseCount > 0);
fUseCount -= 1;
return fArray[fUseCount];
}
template <class T> const T& hsLargeArray<T>::Peek() const
{
hsLargeArray_Validate(fUseCount > 0);
return fArray[fUseCount-1];
}
template <class T> int hsLargeArray<T>::Find(const T& item) const
{
for (int i = 0; i < fUseCount; i++)
if (fArray[i] == item)
return i;
return kMissingIndex;
}
template <class T> hsBool hsLargeArray<T>::RemoveItem(const T& item)
{
for (int i = 0; i < fUseCount; i++)
if (fArray[i] == item)
{ this->DecCount(i, 1);
return true;
}
return false;
}
////////// These are the private methods for hsLargeArray
template <class T> void hsLargeArray_CopyForward(const T src[], T dst[], int count)
{
for (int i = 0; i < count; i++)
dst[i] = src[i];
}
template <class T> void hsLargeArray_CopyBackward(const T src[], T dst[], int count)
{
for (int i = count - 1; i >= 0; --i)
dst[i] = src[i];
}
template <class T> void hsLargeArray<T>::IncCount(int index, int count)
{
int newCount = fUseCount + count;
if (newCount > fTotalCount)
{ if (fTotalCount == 0)
fTotalCount = newCount;
GrowArraySize(newCount); // Sets new fTotalCount
T* newArray = TRACKED_NEW T[fTotalCount];
if (fArray != nil)
{ hsLargeArray_CopyForward(fArray, newArray, index);
hsLargeArray_CopyForward(&fArray[index], &newArray[index + count], fUseCount - index);
delete[] fArray;
}
fArray = newArray;
}
else
hsLargeArray_CopyBackward(&fArray[index], &fArray[index + count], fUseCount - index);
fUseCount = newCount;
}
template <class T> void hsLargeArray<T>::DecCount(int index, int count)
{
if (fUseCount == count)
this->Reset();
else
{ hsLargeArray_CopyForward(&fArray[index + count], &fArray[index], fUseCount - index - count);
fUseCount -= count;
}
}
template <class T> T* hsLargeArray<T>::ForEach(hsBool (*proc)(T&))
{
for (int i = 0; i < fUseCount; i++)
if (proc(fArray[i]))
return &fArray[i];
return nil;
}
template <class T> T* hsLargeArray<T>::ForEach(hsBool (*proc)(T&, void* p1), void* p1)
{
for (int i = 0; i < fUseCount; i++)
if (proc(fArray[i], p1))
return &fArray[i];
return nil;
}
template <class T> T* hsLargeArray<T>::ForEach(hsBool (*proc)(T&, void* p1, void* p2), void* p1, void* p2)
{
for (int i = 0; i < fUseCount; i++)
if (proc(fArray[i], p1, p2))
return &fArray[i];
return nil;
}
#endif