/*==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==*/ /***************************************************************************** * * $/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> #define ARR_MEMORY_FLAGS 0 /*| kMemIgnoreBlock*/ /**************************************************************************** * * 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 (byte 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) FREEFLAGS(m_data, ARR_MEMORY_FLAGS); } //=========================================================================== 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) FREEFLAGS(m_data, ARR_MEMORY_FLAGS); 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) { FREEFLAGS(m_data, ARR_MEMORY_FLAGS); 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 (byte 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 *)REALLOCFLAGS(m_data, bytes, ARR_MEMORY_FLAGS); else if (m_data) { FREEFLAGS(m_data, ARR_MEMORY_FLAGS); m_data = nil; } } //=========================================================================== template void TBuffer::SetCount (unsigned count) { SetBytes(count * sizeof(T)); } //=========================================================================== template void TBuffer::Zero () { if (m_data) MemZero(m_data, 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) { ref(dest); } inline static void Construct (T * dest, unsigned count) { ref(dest); ref(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) { ref(dest); } inline static void Destruct (T * dest, unsigned count) { ref(dest); ref(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) { ref(dest); dest->~T(); } //=========================================================================== template void TArrayCopyObject::Destruct (T * dest, unsigned count) { ref(dest); 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 (byte 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 *)ALLOCFLAGS(count * sizeof(T), ARR_MEMORY_FLAGS); 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 *)ALLOCFLAGS(count * sizeof(T), ARR_MEMORY_FLAGS); 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 *)ALLOCFLAGS(m_count * sizeof(T), ARR_MEMORY_FLAGS); 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) FREEFLAGS(m_data, ARR_MEMORY_FLAGS); } 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) FREEFLAGS(m_data, ARR_MEMORY_FLAGS); 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) FREEFLAGS(m_data, ARR_MEMORY_FLAGS); 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) FREEFLAGS(m_data, ARR_MEMORY_FLAGS); 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 (byte 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); MemZero(m_data, 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); MemZero(m_data + index, 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(m_alloc, source.m_count), 0); C::CopyConstruct(m_data, source.m_data, source.m_count); m_count = source.m_count; return *this; } //=========================================================================== template unsigned TArray::Add (const T & source) { unsigned index = m_count; Push(source); return index; } //=========================================================================== template unsigned TArray::Add (const T * source, unsigned count) { unsigned index = m_count; AdjustSizeChunked(m_count + count, m_count); C::CopyConstruct(&m_data[m_count], source, count); m_count += count; return index; } //=========================================================================== template unsigned TArray::AddArray (const TArray & source) { unsigned index = m_count; AdjustSizeChunked(m_count + source.m_count, m_count); C::CopyConstruct(&m_data[m_count], source.m_data, source.m_count); m_count += source.m_count; return index; } //=========================================================================== template void TArray::AdjustSizeChunked (unsigned newAlloc, unsigned newCount) { // Disallow shrinking the allocation if (newAlloc <= m_alloc) newAlloc = m_alloc; // Process growing the allocation else newAlloc = CalcAllocGrowth(newAlloc, m_alloc, &m_chunkSize); // Perform the allocation 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(m_data + destIndex, m_data + sourceIndex, count); } //=========================================================================== template void TArray::DeleteOrdered (unsigned index) { ASSERT(index < m_count); if (index + 1 < m_count) C::Assign(&m_data[index], &m_data[index + 1], m_count - index - 1); C::Destruct(&m_data[--m_count]); } //=========================================================================== template void TArray::DeleteUnordered (unsigned index) { ASSERT(index < m_count); if (index + 1 < m_count) C::Assign(&m_data[index], &m_data[m_count - 1], 1); C::Destruct(&m_data[--m_count]); } //=========================================================================== template void TArray::GrowToCount (unsigned count, bool zero) { if (count <= m_count) return; AdjustSizeChunked(count, m_count); if (zero) memset(m_data + m_count, 0, (count - m_count) * sizeof(T)); C::Construct(m_data + m_count, count - m_count); m_count = count; } //=========================================================================== template void TArray::GrowToFit (unsigned index, bool zero) { GrowToCount(index + 1, zero); } //=========================================================================== template void TArray::ShrinkBy (unsigned count) { ASSERT(count <= m_count); C::Destruct(m_data + m_count - count, count); m_count -= count; } //=========================================================================== template void TArray::Move (unsigned destIndex, unsigned sourceIndex, unsigned count) { // Copy the data to the destination ASSERT(destIndex + count <= m_count); ASSERT(sourceIndex + count <= m_count); C::Assign(m_data + destIndex, m_data + sourceIndex, count); // Remove it from the source if (destIndex >= sourceIndex) { C::Destruct(m_data + sourceIndex, min(count, destIndex - sourceIndex)); C::Construct(m_data + sourceIndex, min(count, destIndex - sourceIndex)); } else { unsigned overlap = (destIndex + count > sourceIndex) ? (destIndex + count - sourceIndex) : 0; ASSERT(overlap <= count); C::Destruct(m_data + sourceIndex + overlap, count - overlap); C::Construct(m_data + sourceIndex + overlap, count - overlap); } } //=========================================================================== template T * TArray::New () { AdjustSizeChunked(m_count + 1, m_count + 1); return &m_data[m_count - 1]; } //=========================================================================== template T * TArray::New (unsigned count) { AdjustSizeChunked(m_count + count, m_count + count); return &m_data[m_count - count]; } //=========================================================================== template void TArray::Push (const T & source) { AdjustSizeChunked(m_count + 1, m_count); C::CopyConstruct(&m_data[m_count], source); ++m_count; } //=========================================================================== template T TArray::Pop () { ASSERT(m_count); T result = m_data[--m_count]; C::Destruct(m_data + m_count); return result; } //=========================================================================== template void TArray::Reserve (unsigned additionalCount) { AdjustSizeChunked(max(m_alloc, m_count + additionalCount), m_count); } //=========================================================================== template void TArray::Set (const T * source, unsigned count) { AdjustSizeChunked(count, 0); C::CopyConstruct(m_data, source, count); m_count = count; } //=========================================================================== template void TArray::SetChunkSize (unsigned chunkSize) { m_chunkSize = chunkSize; } //=========================================================================== template void TArray::SetCount (unsigned count) { AdjustSizeChunked(max(m_alloc, count), count); } //=========================================================================== template void TArray::SetCountFewer (unsigned count) { ASSERT(count <= m_count); C::Destruct(m_data + count, m_count - count); m_count = count; } //=========================================================================== template void TArray::Trim () { AdjustSize(m_count, m_count); } /**************************************************************************** * * TSortArray * ***/ template class TSortArray : public TArray { private: inline static K & SortKey (T & rec) { return *(K *)((byte *)&rec + OFFSET); } inline static const K & SortKey (const T & rec) { return *(const K *)((const byte *)&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, Ptr(), Count(), (sortKey > SortKey(elem)), &index); // Verify that an entry exists for this key unsigned count = Count(); if ((index >= count) || (SortKey((*this)[index]) != sortKey)) return false; // Delete the entry DeleteOrdered(index); return true; } //=========================================================================== template T * TSortArray::Find (K sortKey, unsigned * index) { // Find the correct position for this key BSEARCH(T, Ptr(), Count(), (sortKey > SortKey(elem)), index); if (*index >= 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, Ptr(), Count(), (sortKey > SortKey(elem)), index); if (*index >= 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 = Count(); SetCount(count + 1); if (index < count) 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 = Ptr(); unsigned count = Count(); QSORT( T, ptr, count, SortKey(elem1) > SortKey(elem2) ); }