/*==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 . Additional permissions under GNU GPL version 3 section 7 If you modify this Program, or any covered work, by linking or combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK (or a modified version of those libraries), containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the licensors of this Program grant you additional permission to convey the resulting work. Corresponding Source for a non-source form of such a combination shall include the source code for the parts of OpenSSL and IJG JPEG Library used as well as that of the covered work. 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==*/ /***************************************************************************** * * $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtArray.h * ***/ #ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTARRAY_H #error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnUtils/Private/pnUtArray.h included more than once" #endif #define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNUTILS_PRIVATE_PNUTARRAY_H /**************************************************************************** * * Macros * ***/ #define ARRAY(type) TArray< type, TArrayCopyBits< type > > #define ARRAYOBJ(type) TArray< type, TArrayCopyObject< type > > #define FARRAY(type) TFArray< type, TArrayCopyBits< type > > #define FARRAYOBJ(type) TFArray< type, TArrayCopyObject< type > > #define SORTARRAYFIELD(type, keyType, field) TSortArray< type, TArrayCopyBits< type >, keyType, offsetof(type, field)> #define SORTARRAYFIELDOBJ(type, keyType, field) TSortArray< type, TArrayCopyObject< type >, keyType, offsetof(type, field)> #define SORTARRAYTYPE(type) TSortArray< type, TArrayCopyBits< type >, type, 0> #define SORTARRAYTYPEOBJ(type) TSortArray< type, TArrayCopyObject< type >, type, 0> /**************************************************************************** * * CBuffer * ***/ template class TBuffer { protected: T * m_data; public: inline TBuffer (); inline TBuffer (unsigned count); inline TBuffer (const void * source, unsigned count); inline TBuffer (const TBuffer & source); inline ~TBuffer (); inline TBuffer & operator= (const TBuffer & source); inline bool operator== (const TBuffer & source) const; inline T & operator[] (unsigned index); inline T operator[] (unsigned index) const; inline void Attach (T * source, unsigned count); inline unsigned Bytes () const; inline void Clear (); inline unsigned Count () const; inline T * Detach (); inline void Fill (uint8_t value); inline T * Ptr (); inline const T * Ptr () const; inline void Set (const T * source, unsigned count); inline void SetBytes (unsigned bytes); inline void SetCount (unsigned count); inline void Zero (); }; //=========================================================================== template TBuffer::TBuffer () { m_data = nil; } //=========================================================================== template TBuffer::TBuffer (unsigned count) { m_data = nil; SetCount(count); } //=========================================================================== template TBuffer::TBuffer (const void * source, unsigned count) { m_data = nil; SetCount(count); memcpy(m_data, source, count * sizeof(T)); } //=========================================================================== template TBuffer::TBuffer (const TBuffer & source) { m_data = nil; unsigned bytes = source.Bytes(); SetBytes(bytes); if (bytes) memcpy(m_data, source.m_data, bytes); } //=========================================================================== template TBuffer::~TBuffer () { if (m_data) free(m_data); } //=========================================================================== template TBuffer & TBuffer::operator= (const TBuffer & source) { unsigned newBytes = source.Bytes(); if (newBytes != Bytes()) SetBytes(newBytes); if (&source != this) memcpy(m_data, source.m_data, newBytes); return *this; } //=========================================================================== template bool TBuffer::operator== (const TBuffer & source) const { unsigned size = MemSize(m_data); return (size == MemSize(source.m_data)) && !memcmp(m_data, source.m_data, size); } //=========================================================================== template T & TBuffer::operator[] (unsigned index) { ASSERT(index < Count()); return m_data[index]; } //=========================================================================== template T TBuffer::operator[] (unsigned index) const { ASSERT(index < Count()); return m_data[index]; } //=========================================================================== template void TBuffer::Attach (T * source, unsigned count) { if (m_data) free(m_data); m_data = source; ASSERT(MemSize(source) >= count * sizeof(T)); } //=========================================================================== template unsigned TBuffer::Bytes () const { return m_data ? MemSize(m_data) : 0; } //=========================================================================== template void TBuffer::Clear () { if (m_data) { free(m_data); m_data = nil; } } //=========================================================================== template unsigned TBuffer::Count () const { return m_data ? (MemSize(m_data) / sizeof(T)) : 0; } //=========================================================================== template T * TBuffer::Detach () { T * result = m_data; m_data = nil; return result; } //=========================================================================== template void TBuffer::Fill (uint8_t value) { if (m_data) memset(m_data, value, Bytes()); } //=========================================================================== template T * TBuffer::Ptr () { return m_data; } //=========================================================================== template const T * TBuffer::Ptr () const { return m_data; } //=========================================================================== template void TBuffer::Set (const T * source, unsigned count) { SetCount(count); memcpy(m_data, source, count * sizeof(T)); } //=========================================================================== template void TBuffer::SetBytes (unsigned bytes) { if (bytes) m_data = (T *)realloc(m_data, bytes); else if (m_data) { free(m_data); m_data = nil; } } //=========================================================================== template void TBuffer::SetCount (unsigned count) { SetBytes(count * sizeof(T)); } //=========================================================================== template void TBuffer::Zero () { if (m_data) memset(m_data, 0, Bytes()); } typedef TBuffer CBuffer; /**************************************************************************** * * CBaseArray * ***/ class CBaseArray { protected: unsigned CalcAllocGrowth (unsigned newAlloc, unsigned oldAlloc, unsigned * chunkSize); void * ReallocPtr (void * ptr, unsigned bytes); }; /**************************************************************************** * * TArrayCopyBits * ***/ template class TArrayCopyBits { public: inline static void Assign (T * dest, const T source[], unsigned count); inline static void Construct (T * dest) { } inline static void Construct (T * dest, unsigned count) { } inline static void CopyConstruct (T * dest, const T & source); inline static void CopyConstruct (T * dest, const T source[], unsigned count); inline static void Destruct (T * dest) { } inline static void Destruct (T * dest, unsigned count) { } }; //=========================================================================== template void TArrayCopyBits::Assign (T * dest, const T source[], unsigned count) { memmove(dest, source, count * sizeof(T)); } //=========================================================================== template void TArrayCopyBits::CopyConstruct (T * dest, const T & source) { *dest = source; } //=========================================================================== template void TArrayCopyBits::CopyConstruct (T * dest, const T source[], unsigned count) { ASSERT((dest + count <= source) || (source + count <= dest)); memcpy(dest, source, count * sizeof(T)); } /**************************************************************************** * * TArrayCopyObject * ***/ template class TArrayCopyObject { public: inline static void Assign (T * dest, const T source[], unsigned count); inline static void Construct (T * dest); inline static void Construct (T * dest, unsigned count); inline static void CopyConstruct (T * dest, const T & source); inline static void CopyConstruct (T * dest, const T source[], unsigned count); inline static void Destruct (T * dest); inline static void Destruct (T * dest, unsigned count); }; //=========================================================================== template void TArrayCopyObject::Assign (T * dest, const T source[], unsigned count) { if (dest > source) for (unsigned loop = count; loop--; ) dest[loop] = source[loop]; else if (dest < source) for (unsigned loop = 0; loop < count; ++loop) dest[loop] = source[loop]; } //=========================================================================== template void TArrayCopyObject::Construct (T * dest) { new(dest) T; } //=========================================================================== template void TArrayCopyObject::Construct (T * dest, unsigned count) { for (unsigned loop = 0; loop < count; ++loop) new(&dest[loop]) T; } //=========================================================================== template void TArrayCopyObject::CopyConstruct (T * dest, const T & source) { new(dest) T(source); } //=========================================================================== template void TArrayCopyObject::CopyConstruct (T * dest, const T source[], unsigned count) { ASSERT((dest + count <= source) || (source + count <= dest)); for (unsigned loop = 0; loop < count; ++loop) new(&dest[loop]) T(source[loop]); } //=========================================================================== template void TArrayCopyObject::Destruct (T * dest) { dest->~T(); } //=========================================================================== template void TArrayCopyObject::Destruct (T * dest, unsigned count) { for (unsigned loop = count; loop--; ) dest[loop].~T(); } /**************************************************************************** * * TFArray * ***/ template class TFArray : protected CBaseArray { protected: T * m_data; unsigned m_alloc; unsigned m_count; inline void AdjustSize (unsigned newAlloc, unsigned newCount); public: inline TFArray (); inline TFArray (unsigned count); inline TFArray (const T * source, unsigned count); inline TFArray (const TFArray & source); inline ~TFArray (); inline TFArray & operator= (const TFArray & source); inline bool operator== (const TFArray & source) const; inline T & operator[] (unsigned index); inline const T & operator[] (unsigned index) const; inline void Attach (T * source, unsigned count); inline void AttachTemp (T * source, unsigned count); inline unsigned Bytes () const; inline void Clear (); inline unsigned Count () const; inline T * Detach (); inline void Fill (uint8_t value); inline T * Ptr (); inline const T * Ptr () const; inline void Set (const T * source, unsigned count); inline void SetArray (const TFArray & source); inline void SetCount (unsigned count); inline T * Term (); inline const T * Term () const; inline T * Top (); inline const T * Top () const; inline void Zero (); inline void ZeroCount (); inline void ZeroRange (unsigned index, unsigned count); }; //=========================================================================== template TFArray::TFArray () { m_alloc = 0; m_count = 0; m_data = nil; } //=========================================================================== template TFArray::TFArray (unsigned count) { m_alloc = m_count = count; if (count) { m_data = (T *)malloc(count * sizeof(T)); C::Construct(m_data, count); } else m_data = nil; } //=========================================================================== template TFArray::TFArray (const T * source, unsigned count) { m_alloc = m_count = count; if (count) { m_data = (T *)malloc(count * sizeof(T)); C::CopyConstruct(m_data, source, count); } else m_data = nil; } //=========================================================================== template TFArray::TFArray (const TFArray & source) { m_alloc = m_count = source.m_count; if (m_count) { m_data = (T *)malloc(m_count * sizeof(T)); C::CopyConstruct(m_data, source.m_data, m_count); } else m_data = nil; } //=========================================================================== template TFArray::~TFArray () { Clear(); } //=========================================================================== template TFArray & TFArray::operator= (const TFArray & source) { if (&source == this) return *this; AdjustSize(source.m_count, 0); C::CopyConstruct(m_data, source.m_data, source.m_count); m_count = source.m_count; return *this; } //=========================================================================== template inline bool TFArray::operator== (const TFArray & source) const { if (m_count != source.m_count) return false; for (unsigned index = 0; index < m_count; ++index) if (!((*this)[index] == source[index])) return false; return true; } //=========================================================================== template T & TFArray::operator[] (unsigned index) { ASSERT(index < m_count); return m_data[index]; } //=========================================================================== template const T & TFArray::operator[] (unsigned index) const { ASSERT(index < m_count); return m_data[index]; } //=========================================================================== template void TFArray::AdjustSize (unsigned newAlloc, unsigned newCount) { // Destruct elements if the array is shrinking if (m_count > newCount) { C::Destruct(m_data + newCount, m_count - newCount); m_count = newCount; } // Change the memory allocation size if necessary if (m_alloc != newAlloc) { T * newData = (T *)ReallocPtr(m_data, newAlloc * sizeof(T)); if (newData != m_data) { C::CopyConstruct(newData, m_data, m_count); C::Destruct(m_data, m_count); if (m_data) free(m_data); } m_alloc = newAlloc; m_data = newData; } // Construct elements if the array is growing if (m_count < newCount) { C::Construct(m_data + m_count, newCount - m_count); m_count = newCount; } } //=========================================================================== template void TFArray::Attach (T * source, unsigned count) { C::Destruct(m_data, m_count); if (m_data) free(m_data); m_data = source; m_alloc = MemSize(source) / sizeof(T); m_count = count; ASSERT(m_alloc >= m_count); } //=========================================================================== template void TFArray::AttachTemp (T * source, unsigned count) { C::Destruct(m_data, m_count); if (m_data) free(m_data); m_data = source; m_alloc = count; m_count = count; } //=========================================================================== template unsigned TFArray::Bytes () const { return m_count * sizeof(T); } //=========================================================================== template void TFArray::Clear () { C::Destruct(m_data, m_count); if (m_data) free(m_data); m_data = nil; m_alloc = m_count = 0; } //=========================================================================== template unsigned TFArray::Count () const { return m_count; } //=========================================================================== template T * TFArray::Detach () { T * result = m_data; m_data = nil; m_alloc = 0; m_count = 0; return result; } //=========================================================================== template void TFArray::Fill (uint8_t value) { C::Destruct(m_data, m_count); memset(m_data, value, m_count * sizeof(T)); C::Construct(m_data, m_count); } //=========================================================================== template T * TFArray::Ptr () { return m_data; } //=========================================================================== template const T * TFArray::Ptr () const { return m_data; } //=========================================================================== template void TFArray::Set (const T * source, unsigned count) { AdjustSize(count, 0); C::CopyConstruct(m_data, source, count); m_count = count; } //=========================================================================== template void TFArray::SetArray (const TFArray & source) { AdjustSize(source.m_count, 0); C::CopyConstruct(m_data, source.m_data, source.m_count); m_count = source.m_count; } //=========================================================================== template void TFArray::SetCount (unsigned count) { AdjustSize(count, count); } //=========================================================================== template T * TFArray::Term () { return m_data + m_count; } //=========================================================================== template const T * TFArray::Term () const { return m_data + m_count; } //=========================================================================== template T * TFArray::Top () { ASSERT(m_count); return m_data + m_count - 1; } //=========================================================================== template const T * TFArray::Top () const { ASSERT(m_count); return m_data + m_count - 1; } //=========================================================================== template void TFArray::Zero () { C::Destruct(m_data, m_count); memset(m_data, 0, m_count * sizeof(T)); C::Construct(m_data, m_count); } //=========================================================================== template void TFArray::ZeroCount () { C::Destruct(m_data, m_count); m_count = 0; } //=========================================================================== template void TFArray::ZeroRange (unsigned index, unsigned count) { ASSERT(index + count <= m_count); C::Destruct(m_data + index, count); memset(m_data + index, 0, count * sizeof(T)); C::Construct(m_data + index, count); } /**************************************************************************** * * TArray * ***/ template class TArray : public TFArray { private: unsigned m_chunkSize; inline void AdjustSizeChunked (unsigned newAlloc, unsigned newCount); public: inline TArray (); inline TArray (const char file[], int line); inline TArray (unsigned count); inline TArray (const T * source, unsigned count); inline TArray (const TArray & source); inline TArray & operator= (const TArray & source); inline unsigned Add (const T & source); inline unsigned Add (const T * source, unsigned count); inline unsigned AddArray (const TArray & source); inline void Copy (unsigned destIndex, unsigned sourceIndex, unsigned count); inline void DeleteOrdered (unsigned index); inline void DeleteUnordered (unsigned index); inline void GrowToCount (unsigned count, bool zero); inline void GrowToFit (unsigned index, bool zero); inline void ShrinkBy (unsigned count); inline void Move (unsigned destIndex, unsigned sourceIndex, unsigned count); inline T * New (); inline T * New (unsigned count); inline void Push (const T & source); inline T Pop (); inline void Reserve (unsigned additionalCount); inline void Set (const T * source, unsigned count); inline void SetChunkSize (unsigned chunkSize); inline void SetCount (unsigned count); inline void SetCountFewer (unsigned count); inline void Trim (); }; //=========================================================================== template TArray::TArray () : TFArray() { m_chunkSize = max(1, 256 / sizeof(T)); } //=========================================================================== template TArray::TArray (const char file[], int line) : TFArray(file, line) { m_chunkSize = max(1, 256 / sizeof(T)); } //=========================================================================== template TArray::TArray (unsigned count) : TFArray(count) { m_chunkSize = max(1, 256 / sizeof(T)); } //=========================================================================== template TArray::TArray (const T * source, unsigned count) : TFArray(source, count) { m_chunkSize = max(1, 256 / sizeof(T)); } //=========================================================================== template TArray::TArray (const TArray & source) : TFArray(source) { m_chunkSize = source.m_chunkSize; } //=========================================================================== template TArray & TArray::operator= (const TArray & source) { if (&source == this) return *this; m_chunkSize = source.m_chunkSize; AdjustSize(max(this->m_alloc, source.m_count), 0); C::CopyConstruct(this->m_data, source.m_data, source.m_count); this->m_count = source.m_count; return *this; } //=========================================================================== template unsigned TArray::Add (const T & source) { unsigned index = this->m_count; Push(source); return index; } //=========================================================================== template unsigned TArray::Add (const T * source, unsigned count) { unsigned index = this->m_count; AdjustSizeChunked(this->m_count + count, this->m_count); C::CopyConstruct(&this->m_data[this->m_count], source, count); this->m_count += count; return index; } //=========================================================================== template unsigned TArray::AddArray (const TArray & source) { unsigned index = this->m_count; AdjustSizeChunked(this->m_count + source.m_count, this->m_count); C::CopyConstruct(&this->m_data[this->m_count], source.m_data, source.m_count); this->m_count += source.m_count; return index; } //=========================================================================== template void TArray::AdjustSizeChunked (unsigned newAlloc, unsigned newCount) { // Disallow shrinking the allocation if (newAlloc <= this->m_alloc) newAlloc = this->m_alloc; // Process growing the allocation else newAlloc = CalcAllocGrowth(newAlloc, this->m_alloc, &this->m_chunkSize); // Perform the allocation this->AdjustSize(newAlloc, newCount); } //=========================================================================== template void TArray::Copy (unsigned destIndex, unsigned sourceIndex, unsigned count) { // Copy the data to the destination ASSERT(destIndex + count <= m_count); ASSERT(sourceIndex + count <= m_count); C::Assign(this->m_data + destIndex, this->m_data + sourceIndex, count); } //=========================================================================== template void TArray::DeleteOrdered (unsigned index) { ASSERT(index < this->m_count); if (index + 1 < this->m_count) C::Assign(&this->m_data[index], &this->m_data[index + 1], this->m_count - index - 1); C::Destruct(&this->m_data[--this->m_count]); } //=========================================================================== template void TArray::DeleteUnordered (unsigned index) { ASSERT(index < this->m_count); if (index + 1 < this->m_count) C::Assign(&this->m_data[index], &this->m_data[this->m_count - 1], 1); C::Destruct(&this->m_data[--this->m_count]); } //=========================================================================== template void TArray::GrowToCount (unsigned count, bool zero) { if (count <= this->m_count) return; AdjustSizeChunked(count, this->m_count); if (zero) memset(this->m_data + this->m_count, 0, (count - this->m_count) * sizeof(T)); C::Construct(this->m_data + this->m_count, count - this->m_count); this->m_count = count; } //=========================================================================== template void TArray::GrowToFit (unsigned index, bool zero) { GrowToCount(index + 1, zero); } //=========================================================================== template void TArray::ShrinkBy (unsigned count) { ASSERT(count <= this->m_count); C::Destruct(this->m_data + this->m_count - count, count); this->m_count -= count; } //=========================================================================== template void TArray::Move (unsigned destIndex, unsigned sourceIndex, unsigned count) { // Copy the data to the destination ASSERT(destIndex + count <= this->m_count); ASSERT(sourceIndex + count <= this->m_count); C::Assign(this->m_data + destIndex, this->m_data + sourceIndex, count); // Remove it from the source if (destIndex >= sourceIndex) { C::Destruct(this->m_data + sourceIndex, min(count, destIndex - sourceIndex)); C::Construct(this->m_data + sourceIndex, min(count, destIndex - sourceIndex)); } else { unsigned overlap = (destIndex + count > sourceIndex) ? (destIndex + count - sourceIndex) : 0; ASSERT(overlap <= count); C::Destruct(this->m_data + sourceIndex + overlap, count - overlap); C::Construct(this->m_data + sourceIndex + overlap, count - overlap); } } //=========================================================================== template T * TArray::New () { AdjustSizeChunked(this->m_count + 1, this->m_count + 1); return &this->m_data[this->m_count - 1]; } //=========================================================================== template T * TArray::New (unsigned count) { AdjustSizeChunked(this->m_count + count, this->m_count + count); return &this->m_data[this->m_count - count]; } //=========================================================================== template void TArray::Push (const T & source) { AdjustSizeChunked(this->m_count + 1, this->m_count); C::CopyConstruct(&this->m_data[this->m_count], source); ++this->m_count; } //=========================================================================== template T TArray::Pop () { ASSERT(this->m_count); T result = this->m_data[--this->m_count]; C::Destruct(this->m_data + this->m_count); return result; } //=========================================================================== template void TArray::Reserve (unsigned additionalCount) { AdjustSizeChunked(max(this->m_alloc, this->m_count + additionalCount), this->m_count); } //=========================================================================== template void TArray::Set (const T * source, unsigned count) { AdjustSizeChunked(count, 0); C::CopyConstruct(this->m_data, source, count); this->m_count = count; } //=========================================================================== template void TArray::SetChunkSize (unsigned chunkSize) { this->m_chunkSize = chunkSize; } //=========================================================================== template void TArray::SetCount (unsigned count) { AdjustSizeChunked(max(this->m_alloc, count), count); } //=========================================================================== template void TArray::SetCountFewer (unsigned count) { ASSERT(count <= this->m_count); C::Destruct(this->m_data + count, this->m_count - count); this->m_count = count; } //=========================================================================== template void TArray::Trim () { this->AdjustSize(this->m_count, this->m_count); } /**************************************************************************** * * TSortArray * ***/ template class TSortArray : public TArray { private: inline static K & SortKey (T & rec) { return *(K *)((uint8_t *)&rec + OFFSET); } inline static const K & SortKey (const T & rec) { return *(const K *)((const uint8_t *)&rec + OFFSET); } public: inline bool Delete (K sortKey); inline T * Find (K sortKey) { unsigned index; return Find(sortKey, &index); } inline T * Find (K sortKey, unsigned * index); inline const T * Find (K sortKey) const { unsigned index; return Find(sortKey, &index); } inline const T * Find (K sortKey, unsigned * index) const; inline T * Insert (K sortKey, unsigned index); inline void Sort (); }; //=========================================================================== template bool TSortArray::Delete (K sortKey) { // Find the correct position for this key unsigned index; BSEARCH(T, this->Ptr(), this->Count(), (sortKey > SortKey(elem)), &index); // Verify that an entry exists for this key unsigned count = this->Count(); if ((index >= count) || (SortKey((*this)[index]) != sortKey)) return false; // Delete the entry this->DeleteOrdered(index); return true; } //=========================================================================== template T * TSortArray::Find (K sortKey, unsigned * index) { // Find the correct position for this key BSEARCH(T, this->Ptr(), this->Count(), (sortKey > SortKey(elem)), index); if (*index >= this->Count()) return nil; // Check whether the key is at that position T & elem = (*this)[*index]; return (SortKey(elem) == sortKey) ? &elem : nil; } //=========================================================================== template const T * TSortArray::Find (K sortKey, unsigned * index) const { // Find the correct position for this key BSEARCH(T, this->Ptr(), this->Count(), (sortKey > SortKey(elem)), index); if (*index >= this->Count()) return nil; // Check whether the key is at that position const T & elem = (*this)[*index]; return (SortKey(elem) == sortKey) ? &elem : nil; } //=========================================================================== template T * TSortArray::Insert (K sortKey, unsigned index) { // Insert a new entry at this position unsigned count = this->Count(); this->SetCount(count + 1); if (index < count) this->Move(index + 1, index, count - index); // Fill in the new entry T & elem = (*this)[index]; SortKey(elem) = sortKey; return &elem; } //=========================================================================== template void TSortArray::Sort () { T * ptr = this->Ptr(); unsigned count = this->Count(); QSORT( T, ptr, count, SortKey(elem1) > SortKey(elem2) ); }