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.
1088 lines
34 KiB
1088 lines
34 KiB
4 years ago
|
/*==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/>.
|
||
|
|
||
|
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>
|
||
|
|
||
|
#define ARR_MEMORY_FLAGS 0 /*| kMemIgnoreBlock*/
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* CBuffer
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
template<class T>
|
||
|
class TBuffer {
|
||
|
|
||
|
protected:
|
||
|
T * m_data;
|
||
|
|
||
|
public:
|
||
|
inline TBuffer ();
|
||
|
inline TBuffer (unsigned count);
|
||
|
inline TBuffer (const void * source, unsigned count);
|
||
|
inline TBuffer (const TBuffer<T> & source);
|
||
|
inline ~TBuffer ();
|
||
|
inline TBuffer<T> & operator= (const TBuffer<T> & source);
|
||
|
inline bool operator== (const TBuffer<T> & 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<class T>
|
||
|
TBuffer<T>::TBuffer () {
|
||
|
m_data = nil;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
TBuffer<T>::TBuffer (unsigned count) {
|
||
|
m_data = nil;
|
||
|
SetCount(count);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
TBuffer<T>::TBuffer (const void * source, unsigned count) {
|
||
|
m_data = nil;
|
||
|
SetCount(count);
|
||
|
memcpy(m_data, source, count * sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
TBuffer<T>::TBuffer (const TBuffer<T> & source) {
|
||
|
m_data = nil;
|
||
|
unsigned bytes = source.Bytes();
|
||
|
SetBytes(bytes);
|
||
|
if (bytes)
|
||
|
memcpy(m_data, source.m_data, bytes);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
TBuffer<T>::~TBuffer () {
|
||
|
if (m_data)
|
||
|
FREEFLAGS(m_data, ARR_MEMORY_FLAGS);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
TBuffer<T> & TBuffer<T>::operator= (const TBuffer<T> & source) {
|
||
|
unsigned newBytes = source.Bytes();
|
||
|
if (newBytes != Bytes())
|
||
|
SetBytes(newBytes);
|
||
|
if (&source != this)
|
||
|
memcpy(m_data, source.m_data, newBytes);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
bool TBuffer<T>::operator== (const TBuffer<T> & source) const {
|
||
|
unsigned size = MemSize(m_data);
|
||
|
return (size == MemSize(source.m_data)) && !MemCmp(m_data, source.m_data, size);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
T & TBuffer<T>::operator[] (unsigned index) {
|
||
|
ASSERT(index < Count());
|
||
|
return m_data[index];
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
T TBuffer<T>::operator[] (unsigned index) const {
|
||
|
ASSERT(index < Count());
|
||
|
return m_data[index];
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TBuffer<T>::Attach (T * source, unsigned count) {
|
||
|
if (m_data)
|
||
|
FREEFLAGS(m_data, ARR_MEMORY_FLAGS);
|
||
|
m_data = source;
|
||
|
ASSERT(MemSize(source) >= count * sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
unsigned TBuffer<T>::Bytes () const {
|
||
|
return m_data ? MemSize(m_data) : 0;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TBuffer<T>::Clear () {
|
||
|
if (m_data) {
|
||
|
FREEFLAGS(m_data, ARR_MEMORY_FLAGS);
|
||
|
m_data = nil;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
unsigned TBuffer<T>::Count () const {
|
||
|
return m_data ? (MemSize(m_data) / sizeof(T)) : 0;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
T * TBuffer<T>::Detach () {
|
||
|
T * result = m_data;
|
||
|
m_data = nil;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TBuffer<T>::Fill (byte value) {
|
||
|
if (m_data)
|
||
|
MemSet(m_data, value, Bytes());
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
T * TBuffer<T>::Ptr () {
|
||
|
return m_data;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
const T * TBuffer<T>::Ptr () const {
|
||
|
return m_data;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TBuffer<T>::Set (const T * source, unsigned count) {
|
||
|
SetCount(count);
|
||
|
memcpy(m_data, source, count * sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TBuffer<T>::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<class T>
|
||
|
void TBuffer<T>::SetCount (unsigned count) {
|
||
|
SetBytes(count * sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TBuffer<T>::Zero () {
|
||
|
if (m_data)
|
||
|
MemZero(m_data, Bytes());
|
||
|
}
|
||
|
|
||
|
typedef TBuffer<byte> CBuffer;
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* CBaseArray
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
class CBaseArray {
|
||
|
protected:
|
||
|
unsigned CalcAllocGrowth (unsigned newAlloc, unsigned oldAlloc, unsigned * chunkSize);
|
||
|
void * ReallocPtr (void * ptr, unsigned bytes);
|
||
|
};
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* TArrayCopyBits
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
template<class T>
|
||
|
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<class T>
|
||
|
void TArrayCopyBits<T>::Assign (T * dest, const T source[], unsigned count) {
|
||
|
MemMove(dest, source, count * sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TArrayCopyBits<T>::CopyConstruct (T * dest, const T & source) {
|
||
|
*dest = source;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TArrayCopyBits<T>::CopyConstruct (T * dest, const T source[], unsigned count) {
|
||
|
ASSERT((dest + count <= source) || (source + count <= dest));
|
||
|
memcpy(dest, source, count * sizeof(T));
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* TArrayCopyObject
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
template<class T>
|
||
|
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<class T>
|
||
|
void TArrayCopyObject<T>::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<class T>
|
||
|
void TArrayCopyObject<T>::Construct (T * dest) {
|
||
|
new(dest) T;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TArrayCopyObject<T>::Construct (T * dest, unsigned count) {
|
||
|
for (unsigned loop = 0; loop < count; ++loop)
|
||
|
new(&dest[loop]) T;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TArrayCopyObject<T>::CopyConstruct (T * dest, const T & source) {
|
||
|
new(dest) T(source);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TArrayCopyObject<T>::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<class T>
|
||
|
void TArrayCopyObject<T>::Destruct (T * dest) {
|
||
|
REF(dest);
|
||
|
dest->~T();
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T>
|
||
|
void TArrayCopyObject<T>::Destruct (T * dest, unsigned count) {
|
||
|
REF(dest);
|
||
|
for (unsigned loop = count; loop--; )
|
||
|
dest[loop].~T();
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* TFArray
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
template<class T, class C>
|
||
|
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<T,C> & source);
|
||
|
inline ~TFArray ();
|
||
|
inline TFArray<T,C> & operator= (const TFArray<T,C> & source);
|
||
|
inline bool operator== (const TFArray<T,C> & 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<T,C> & 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<class T, class C>
|
||
|
TFArray<T,C>::TFArray () {
|
||
|
m_alloc = 0;
|
||
|
m_count = 0;
|
||
|
m_data = nil;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
TFArray<T,C>::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<class T, class C>
|
||
|
TFArray<T,C>::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<class T, class C>
|
||
|
TFArray<T,C>::TFArray (const TFArray<T,C> & 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<class T, class C>
|
||
|
TFArray<T,C>::~TFArray () {
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
TFArray<T,C> & TFArray<T,C>::operator= (const TFArray<T,C> & 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<class T, class C>
|
||
|
inline bool TFArray<T,C>::operator== (const TFArray<T,C> & 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<class T, class C>
|
||
|
T & TFArray<T,C>::operator[] (unsigned index) {
|
||
|
ASSERT(index < m_count);
|
||
|
return m_data[index];
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
const T & TFArray<T,C>::operator[] (unsigned index) const {
|
||
|
ASSERT(index < m_count);
|
||
|
return m_data[index];
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::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<class T, class C>
|
||
|
void TFArray<T,C>::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<class T, class C>
|
||
|
void TFArray<T,C>::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<class T, class C>
|
||
|
unsigned TFArray<T,C>::Bytes () const {
|
||
|
return m_count * sizeof(T);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::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<class T, class C>
|
||
|
unsigned TFArray<T,C>::Count () const {
|
||
|
return m_count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
T * TFArray<T,C>::Detach () {
|
||
|
T * result = m_data;
|
||
|
m_data = nil;
|
||
|
m_alloc = 0;
|
||
|
m_count = 0;
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::Fill (byte value) {
|
||
|
C::Destruct(m_data, m_count);
|
||
|
MemSet(m_data, value, m_count * sizeof(T));
|
||
|
C::Construct(m_data, m_count);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
T * TFArray<T,C>::Ptr () {
|
||
|
return m_data;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
const T * TFArray<T,C>::Ptr () const {
|
||
|
return m_data;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::Set (const T * source, unsigned count) {
|
||
|
AdjustSize(count, 0);
|
||
|
C::CopyConstruct(m_data, source, count);
|
||
|
m_count = count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::SetArray (const TFArray<T,C> & source) {
|
||
|
AdjustSize(source.m_count, 0);
|
||
|
C::CopyConstruct(m_data, source.m_data, source.m_count);
|
||
|
m_count = source.m_count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::SetCount (unsigned count) {
|
||
|
AdjustSize(count, count);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
T * TFArray<T,C>::Term () {
|
||
|
return m_data + m_count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
const T * TFArray<T,C>::Term () const {
|
||
|
return m_data + m_count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
T * TFArray<T,C>::Top () {
|
||
|
ASSERT(m_count);
|
||
|
return m_data + m_count - 1;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
const T * TFArray<T,C>::Top () const {
|
||
|
ASSERT(m_count);
|
||
|
return m_data + m_count - 1;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::Zero () {
|
||
|
C::Destruct(m_data, m_count);
|
||
|
MemZero(m_data, m_count * sizeof(T));
|
||
|
C::Construct(m_data, m_count);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::ZeroCount () {
|
||
|
C::Destruct(m_data, m_count);
|
||
|
m_count = 0;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TFArray<T,C>::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 T, class C>
|
||
|
class TArray : public TFArray<T,C> {
|
||
|
|
||
|
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<T,C> & source);
|
||
|
inline TArray<T,C> & operator= (const TArray<T,C> & source);
|
||
|
inline unsigned Add (const T & source);
|
||
|
inline unsigned Add (const T * source, unsigned count);
|
||
|
inline unsigned AddArray (const TArray<T,C> & 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<class T, class C>
|
||
|
TArray<T,C>::TArray () : TFArray<T,C>() {
|
||
|
m_chunkSize = max(1, 256 / sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
TArray<T,C>::TArray (const char file[], int line) : TFArray<T,C>(file, line) {
|
||
|
m_chunkSize = max(1, 256 / sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
TArray<T,C>::TArray (unsigned count) : TFArray<T,C>(count) {
|
||
|
m_chunkSize = max(1, 256 / sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
TArray<T,C>::TArray (const T * source, unsigned count) : TFArray<T,C>(source, count) {
|
||
|
m_chunkSize = max(1, 256 / sizeof(T));
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
TArray<T,C>::TArray (const TArray & source) : TFArray<T,C>(source) {
|
||
|
m_chunkSize = source.m_chunkSize;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
TArray<T,C> & TArray<T,C>::operator= (const TArray<T,C> & 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<class T, class C>
|
||
|
unsigned TArray<T,C>::Add (const T & source) {
|
||
|
unsigned index = m_count;
|
||
|
Push(source);
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
unsigned TArray<T,C>::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<class T, class C>
|
||
|
unsigned TArray<T,C>::AddArray (const TArray<T,C> & 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<class T, class C>
|
||
|
void TArray<T,C>::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<class T, class C>
|
||
|
void TArray<T,C>::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<class T, class C>
|
||
|
void TArray<T,C>::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<class T, class C>
|
||
|
void TArray<T,C>::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<class T, class C>
|
||
|
void TArray<T,C>::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<class T, class C>
|
||
|
void TArray<T,C>::GrowToFit (unsigned index, bool zero) {
|
||
|
GrowToCount(index + 1, zero);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::ShrinkBy (unsigned count) {
|
||
|
ASSERT(count <= m_count);
|
||
|
C::Destruct(m_data + m_count - count, count);
|
||
|
m_count -= count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::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<class T, class C>
|
||
|
T * TArray<T,C>::New () {
|
||
|
AdjustSizeChunked(m_count + 1, m_count + 1);
|
||
|
return &m_data[m_count - 1];
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
T * TArray<T,C>::New (unsigned count) {
|
||
|
AdjustSizeChunked(m_count + count, m_count + count);
|
||
|
return &m_data[m_count - count];
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::Push (const T & source) {
|
||
|
AdjustSizeChunked(m_count + 1, m_count);
|
||
|
C::CopyConstruct(&m_data[m_count], source);
|
||
|
++m_count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
T TArray<T,C>::Pop () {
|
||
|
ASSERT(m_count);
|
||
|
T result = m_data[--m_count];
|
||
|
C::Destruct(m_data + m_count);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::Reserve (unsigned additionalCount) {
|
||
|
AdjustSizeChunked(max(m_alloc, m_count + additionalCount), m_count);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::Set (const T * source, unsigned count) {
|
||
|
AdjustSizeChunked(count, 0);
|
||
|
C::CopyConstruct(m_data, source, count);
|
||
|
m_count = count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::SetChunkSize (unsigned chunkSize) {
|
||
|
m_chunkSize = chunkSize;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::SetCount (unsigned count) {
|
||
|
AdjustSizeChunked(max(m_alloc, count), count);
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::SetCountFewer (unsigned count) {
|
||
|
ASSERT(count <= m_count);
|
||
|
C::Destruct(m_data + count, m_count - count);
|
||
|
m_count = count;
|
||
|
}
|
||
|
|
||
|
//===========================================================================
|
||
|
template<class T, class C>
|
||
|
void TArray<T,C>::Trim () {
|
||
|
AdjustSize(m_count, m_count);
|
||
|
}
|
||
|
|
||
|
|
||
|
/****************************************************************************
|
||
|
*
|
||
|
* TSortArray
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
template<class T, class C, class K, unsigned OFFSET>
|
||
|
class TSortArray : public TArray<T,C> {
|
||
|
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<class T, class C, class K, unsigned OFFSET>
|
||
|
bool TSortArray<T,C,K,OFFSET>::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<class T, class C, class K, unsigned OFFSET>
|
||
|
T * TSortArray<T,C,K,OFFSET>::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<class T, class C, class K, unsigned OFFSET>
|
||
|
const T * TSortArray<T,C,K,OFFSET>::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<class T, class C, class K, unsigned OFFSET>
|
||
|
T * TSortArray<T,C,K,OFFSET>::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<class T, class C, class K, unsigned OFFSET>
|
||
|
void TSortArray<T,C,K,OFFSET>::Sort () {
|
||
|
T * ptr = Ptr();
|
||
|
unsigned count = Count();
|
||
|
QSORT(
|
||
|
T,
|
||
|
ptr,
|
||
|
count,
|
||
|
SortKey(elem1) > SortKey(elem2)
|
||
|
);
|
||
|
}
|