/*==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 . 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 #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 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 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 hsTempArray { T* fArray; UInt32 fCount; hsTempArray& operator=(const hsTempArray&); 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 hsDynamicArray { private: Int32 fCount; T* fArray; hsDynamicArray& operator=(const hsDynamicArray&); // 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* Copy(hsDynamicArray* 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 hsDynamicArrayAccess { T* fArray; hsDynamicArray *fArrayObj; hsDynamicArrayAccess& operator=(const hsDynamicArrayAccess&); public: hsDynamicArrayAccess(hsDynamicArray *array) : fArrayObj(array) { fArray = array->AcquireArray();} ~hsDynamicArrayAccess() { fArrayObj->ReleaseArray(fArray); } operator T*() const { return fArray; } T* operator->() const { return fArray; } }; template hsDynamicArray::hsDynamicArray(Int32 count) { fCount = count; fArray = nil; if (count) fArray = TRACKED_NEW T[ count ]; } template hsDynamicArray::~hsDynamicArray() { this->Reset(); } template void hsDynamicArray::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 T& hsDynamicArray::operator[]( Int32 index ) { hsDebugCode(hsThrowIfBadParam((UInt32)index >= (UInt32)fCount);) return fArray[index]; } template const T& hsDynamicArray::Get( Int32 index ) const { hsDebugCode(hsThrowIfBadParam((UInt32)index >= (UInt32)fCount);) return fArray[index]; } template Int32 hsDynamicArray::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 Int32 hsDynamicArray::Find(const T& obj) const { for (int i = 0; i < fCount; i++) if (fArray[i] == obj) return i; return kMissingIndex; } template void hsDynamicArray::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 Int32 hsDynamicArray::Pop(T *obj) { hsThrowIfBadParam(this->IsEmpty()); *obj = fArray[0]; Remove(0); return fCount; } template Int32 hsDynamicArray::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 Int32 hsDynamicArray::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 Int32 hsDynamicArray::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 void hsDynamicArray::Reset() { if (fArray) { delete[] fArray; fArray = nil; fCount = 0; } } template hsDynamicArray* hsDynamicArray::Copy(hsDynamicArray* dst) const { if (dst == nil) dst = TRACKED_NEW hsDynamicArray; else dst->Reset(); dst->SetCount(this->fCount); for (int i = 0; i < this->fCount; i++) dst->fArray[i] = this->fArray[i]; return dst; } template T* hsDynamicArray::ForEach(Boolean (*proc)(T&)) { for (int i = 0; i < fCount; i++) if (proc(fArray[i])) return &fArray[i]; return nil; } template T* hsDynamicArray::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 T* hsDynamicArray::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 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& src); ~hsTArray() { if (fArray) delete[] fArray; } inline void Expand(int NewTotal); inline hsTArray& operator=(const hsTArray& src); bool operator==(const hsTArray& src) const; // checks sizes and contents // Swaps the internal data (including the fArray POINTER) with the data from the array given void Swap( hsTArray& 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 hsTArray::hsTArray(int count) : fArray(nil) { hsTArray_ValidateCount(count); fUseCount = fTotalCount = count; if (count > 0) fArray = TRACKED_NEW T[count]; } template hsTArray::hsTArray(const hsTArray& 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 hsTArray& hsTArray::operator=(const hsTArray& src) { if (this->Count() != src.Count()) this->SetCount(src.Count()); hsTArray_CopyForward(src.fArray, fArray, src.Count()); return *this; } // checks sizes and contents template bool hsTArray::operator==(const hsTArray& src) const { if (&src==this) return true; // it's me if (GetCount() != src.GetCount()) return false; // different sizes int i; for(i=0;i void hsTArray::Swap( hsTArray& 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 void hsTArray::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 void hsTArray::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 void hsTArray::SetCount(int count) { hsTArray_ValidateCount(count); if (count > fTotalCount) { if (fArray) delete[] fArray; fArray = TRACKED_NEW T[count]; fUseCount = fTotalCount = count; } fUseCount = count; } template void hsTArray::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 void hsTArray::Reset() { if (fArray) { delete[] fArray; fArray = nil; fUseCount = fTotalCount = 0; } } template T hsTArray::Pop() { hsTArray_Validate(fUseCount > 0); fUseCount -= 1; return fArray[fUseCount]; } template const T& hsTArray::Peek() const { hsTArray_Validate(fUseCount > 0); return fArray[fUseCount-1]; } template int hsTArray::Find(const T& item) const { for (int i = 0; i < fUseCount; i++) if (fArray[i] == item) return i; return kMissingIndex; } template hsBool hsTArray::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 void hsTArray_CopyForward(const T src[], T dst[], int count) { for (int i = 0; i < count; i++) dst[i] = src[i]; } template void hsTArray_CopyBackward(const T src[], T dst[], int count) { for (int i = count - 1; i >= 0; --i) dst[i] = src[i]; } template void hsTArray::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 void hsTArray::DecCount(int index, int count) { if (fUseCount == count) this->Reset(); else { hsTArray_CopyForward(&fArray[index + count], &fArray[index], fUseCount - index - count); fUseCount -= count; } } template T* hsTArray::ForEach(hsBool (*proc)(T&)) { for (int i = 0; i < fUseCount; i++) if (proc(fArray[i])) return &fArray[i]; return nil; } template T* hsTArray::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 T* hsTArray::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 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& src); ~hsLargeArray() { if (fArray) delete[] fArray; } inline void Expand(int NewTotal); inline hsLargeArray& operator=(const hsLargeArray& src); // Swaps the internal data (including the fArray POINTER) with the data from the array given void Swap( hsLargeArray& 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 hsLargeArray::hsLargeArray(int count) : fArray(nil) { hsLargeArray_ValidateCount(count); fUseCount = fTotalCount = count; if (count > 0) fArray = TRACKED_NEW T[count]; } template hsLargeArray::hsLargeArray(const hsLargeArray& 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 hsLargeArray& hsLargeArray::operator=(const hsLargeArray& src) { if (this->Count() != src.Count()) this->SetCount(src.Count()); hsLargeArray_CopyForward(src.fArray, fArray, src.Count()); return *this; } template void hsLargeArray::Swap( hsLargeArray& 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 void hsLargeArray::SetCountAndZero(int count) { if( fTotalCount <= count ) { int n = fTotalCount; Expand(count); } HSMemory::Clear(fArray, fTotalCount * sizeof( T )); fUseCount = count; } template void hsLargeArray::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 void hsLargeArray::SetCount(int count) { hsLargeArray_ValidateCount(count); if (count > fTotalCount) { if (fArray) delete[] fArray; fArray = TRACKED_NEW T[count]; fUseCount = fTotalCount = count; } fUseCount = count; } template void hsLargeArray::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 void hsLargeArray::Reset() { if (fArray) { delete[] fArray; fArray = nil; fUseCount = fTotalCount = 0; } } template T hsLargeArray::Pop() { hsLargeArray_Validate(fUseCount > 0); fUseCount -= 1; return fArray[fUseCount]; } template const T& hsLargeArray::Peek() const { hsLargeArray_Validate(fUseCount > 0); return fArray[fUseCount-1]; } template int hsLargeArray::Find(const T& item) const { for (int i = 0; i < fUseCount; i++) if (fArray[i] == item) return i; return kMissingIndex; } template hsBool hsLargeArray::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 void hsLargeArray_CopyForward(const T src[], T dst[], int count) { for (int i = 0; i < count; i++) dst[i] = src[i]; } template void hsLargeArray_CopyBackward(const T src[], T dst[], int count) { for (int i = count - 1; i >= 0; --i) dst[i] = src[i]; } template void hsLargeArray::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 void hsLargeArray::DecCount(int index, int count) { if (fUseCount == count) this->Reset(); else { hsLargeArray_CopyForward(&fArray[index + count], &fArray[index], fUseCount - index - count); fUseCount -= count; } } template T* hsLargeArray::ForEach(hsBool (*proc)(T&)) { for (int i = 0; i < fUseCount; i++) if (proc(fArray[i])) return &fArray[i]; return nil; } template T* hsLargeArray::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 T* hsLargeArray::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