259 lines
7.3 KiB
C++
259 lines
7.3 KiB
C++
#ifndef __ARRAY_H__
|
|
#define __ARRAY_H__
|
|
|
|
class CPtrArray
|
|
{
|
|
public:
|
|
// Granularity
|
|
|
|
void SetGranularity( int nGrowBy ) { if(nGrowBy >= 0) m_nGrowBy = nGrowBy;}
|
|
|
|
// Construction
|
|
CPtrArray();
|
|
|
|
// Attributes
|
|
int GetSize();
|
|
int GetUpperBound();
|
|
void SetSize(int nNewSize, int nGrowBy = -1);
|
|
|
|
// Operations
|
|
// Clean up
|
|
void FreeExtra();
|
|
void RemoveAll();
|
|
|
|
// Accessing elements
|
|
void* GetAt(int nIndex) const;
|
|
void SetAt(int nIndex, void* newElement);
|
|
void*& ElementAt(int nIndex);
|
|
|
|
// overloaded operator helpers
|
|
void* operator[](int nIndex) const;
|
|
void*& operator[](int nIndex);
|
|
|
|
// Direct Access to the element data (may return NULL)
|
|
const void** GetData() const;
|
|
void** GetData();
|
|
|
|
// Potentially growing the array
|
|
void SetAtGrow(int nIndex, void* newElement);
|
|
int Add(void* newElement);
|
|
|
|
// Operations that move elements around
|
|
void InsertAt(int nIndex, void* newElement, int nCount = 1);
|
|
void RemoveAt(int nIndex, int nCount = 1);
|
|
void InsertAt(int nStartIndex, CPtrArray* pNewArray);
|
|
|
|
// Implementation
|
|
protected:
|
|
void** m_pData; // the actual array of data
|
|
int m_nSize; // # of elements (upperBound - 1)
|
|
int m_nMaxSize; // max allocated
|
|
int m_nGrowBy; // grow amount
|
|
|
|
public:
|
|
~CPtrArray();
|
|
};
|
|
|
|
inline int CPtrArray::GetSize() { return m_nSize; }
|
|
inline int CPtrArray::GetUpperBound() { return m_nSize-1; }
|
|
inline void CPtrArray::RemoveAll() { SetSize(0); }
|
|
inline void* CPtrArray::GetAt(int nIndex) const { if(nIndex < 0 || nIndex >= m_nSize) return NULL; return m_pData[nIndex]; }
|
|
inline void CPtrArray::SetAt(int nIndex, void* newElement) { if(nIndex < 0 || nIndex >= m_nSize) return; m_pData[nIndex] = newElement; }
|
|
inline int CPtrArray::Add(void* newElement) { int nIndex = m_nSize; SetAtGrow(nIndex, newElement); return nIndex; }
|
|
inline void*& CPtrArray::ElementAt(int nIndex){if(nIndex < 0 || nIndex >= m_nSize){void ** res = NULL; return *res;} return m_pData[nIndex]; }
|
|
inline const void** CPtrArray::GetData() const { return (const void**)m_pData; }
|
|
inline void** CPtrArray::GetData() { return (void**)m_pData; }
|
|
inline void* CPtrArray::operator[](int nIndex) const { return GetAt(nIndex); }
|
|
inline void*& CPtrArray::operator[](int nIndex) { return ElementAt(nIndex); }
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTypedPtrArray<TYPE>
|
|
|
|
template<class TYPE>
|
|
class CTypedPtrArray : public CPtrArray
|
|
{
|
|
public:
|
|
// Accessing elements
|
|
TYPE GetAt(int nIndex) const
|
|
{ return (TYPE)CPtrArray::GetAt(nIndex); }
|
|
TYPE& ElementAt(int nIndex)
|
|
{ return (TYPE&)CPtrArray::ElementAt(nIndex); }
|
|
|
|
// overloaded operator helpers
|
|
TYPE operator[](int nIndex) const
|
|
{ return (TYPE)CPtrArray::operator[](nIndex); }
|
|
TYPE& operator[](int nIndex)
|
|
{ return (TYPE&)CPtrArray::operator[](nIndex); }
|
|
// Deleting Elements
|
|
void DeleteAt(int nIndex);
|
|
void DeleteAll();
|
|
};
|
|
|
|
// Deleting Elements
|
|
template<class TYPE>
|
|
void CTypedPtrArray<TYPE>::DeleteAt(int nIndex)
|
|
{
|
|
TYPE p;
|
|
p = GetAt(nIndex);
|
|
RemoveAt(nIndex);
|
|
if(p) delete p;
|
|
}
|
|
|
|
|
|
template<class TYPE>
|
|
void CTypedPtrArray<TYPE>::DeleteAll()
|
|
{
|
|
TYPE p;
|
|
for(int i = GetUpperBound(); i>=0; i--)
|
|
if(p = GetAt(i)) delete p;
|
|
RemoveAll();
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CSTPArray<TYPE> > class Sorted Typed Pointer Array
|
|
// Created byCatalin Cocos
|
|
template<class TYPE>
|
|
class CSTPArray : public CTypedPtrArray<TYPE*>
|
|
{
|
|
static CRITICAL_SECTION m_CriticalSection;
|
|
static int m_iNumObjects;
|
|
static int m_qsort_Key;
|
|
int m_iKey;
|
|
static int SCompare(TYPE**,TYPE**);
|
|
public:
|
|
// Constructor
|
|
CSTPArray(int iKey = 0);
|
|
// Destructor
|
|
~CSTPArray();
|
|
// Sorting elements
|
|
void QSort(int iKey = 0);
|
|
// Adding elements
|
|
int SAdd(TYPE* newElement, BOOL & NotAdded, BOOL AdmitDuplicates = TRUE);
|
|
// Searching elements
|
|
int Index(TYPE* newElement, int *p_iidx = NULL);
|
|
int UpperBound(int idx);
|
|
int LowerBound(int idx);
|
|
};
|
|
|
|
// the static members
|
|
template<class TYPE>
|
|
int CSTPArray<TYPE>::m_iNumObjects = 0;
|
|
template<class TYPE>
|
|
int CSTPArray<TYPE>::m_qsort_Key = 0;
|
|
template<class TYPE>
|
|
CRITICAL_SECTION CSTPArray<TYPE>::m_CriticalSection;
|
|
|
|
|
|
// Constructor
|
|
template<class TYPE>
|
|
CSTPArray<TYPE>::CSTPArray(int iKey)
|
|
{
|
|
m_iKey = iKey;
|
|
if(!m_iNumObjects++)
|
|
InitializeCriticalSection(&m_CriticalSection);
|
|
}
|
|
|
|
// Destructor
|
|
template<class TYPE>
|
|
CSTPArray<TYPE>::~CSTPArray()
|
|
{
|
|
if(!--m_iNumObjects)
|
|
DeleteCriticalSection(&m_CriticalSection);
|
|
}
|
|
|
|
// sorting the array
|
|
template<class TYPE>
|
|
int CSTPArray<TYPE>::SCompare(TYPE** a,TYPE** b)
|
|
{
|
|
return TYPE::Compare(*a,*b,m_qsort_Key);
|
|
}
|
|
|
|
template<class TYPE>
|
|
void CSTPArray<TYPE>::QSort(int iKey)
|
|
{
|
|
EnterCriticalSection(&m_CriticalSection);
|
|
m_qsort_Key = m_iKey = iKey;
|
|
qsort(GetData(),GetSize(),sizeof(TYPE*),(int (*)(const void *,const void *))SCompare);
|
|
LeaveCriticalSection(&m_CriticalSection);
|
|
}
|
|
|
|
// Adding elements
|
|
|
|
template<class TYPE>
|
|
int CSTPArray<TYPE>::SAdd(TYPE* newElement, BOOL& NotAdded, BOOL AdmitDuplicates )
|
|
{
|
|
int iidx, idx = Index( newElement, &iidx );
|
|
NotAdded = idx>=0 && ( !AdmitDuplicates || (newElement == GetAt(idx)) );
|
|
return (NotAdded? idx: InsertAt(iidx, newElement, 1),iidx );
|
|
}
|
|
|
|
// Searching elements
|
|
template<class TYPE>
|
|
int CSTPArray<TYPE>::Index(TYPE* newElement, int *p_iidx)
|
|
{
|
|
if(p_iidx) *p_iidx = 0;
|
|
if(!newElement) return -1;
|
|
int hidx = GetUpperBound(), lidx = 0, cidx, val;
|
|
if(hidx<0) return hidx;
|
|
while(hidx > lidx)
|
|
{
|
|
val = TYPE::Compare(newElement,GetAt(cidx = (hidx+lidx)/2),m_iKey);
|
|
if( !val ) hidx = lidx = cidx;
|
|
else if( val<0 ) hidx = cidx;
|
|
else lidx = cidx+1;
|
|
}
|
|
if(p_iidx) *p_iidx = lidx+1;
|
|
val = TYPE::Compare(newElement,GetAt(lidx),m_iKey);
|
|
if( !val )
|
|
{
|
|
if(p_iidx) *p_iidx = lidx+1;
|
|
return lidx;
|
|
}
|
|
else if( val<0 )
|
|
{
|
|
if(p_iidx) (*p_iidx)--;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// finding the bounds of equivalence intervals (upper & lower)
|
|
template<class TYPE>
|
|
int CSTPArray<TYPE>::UpperBound(int idx)
|
|
{
|
|
int Midx = GetUpperBound(), lidx, hidx, cidx; // the upper limit
|
|
if(idx<0 || idx>=Midx ) return Midx; // the item is out of bounds or the last in the array
|
|
TYPE* pCrt = GetAt(lidx = hidx = idx); // this is the target
|
|
// if the last element of the array is <=> with the target, return its index (no use for further search)
|
|
if(!TYPE::Compare(pCrt,GetAt(Midx),m_iKey)) return Midx;
|
|
// find the interval bound (kinda' confusing method, isn't it?)
|
|
for(hidx ++ ;!TYPE::Compare(pCrt,GetAt(hidx),m_iKey); lidx = hidx, hidx = min(Midx,idx+(hidx-idx)*2));
|
|
hidx--;
|
|
while(hidx > lidx)
|
|
if(TYPE::Compare(pCrt,GetAt(cidx = (hidx+lidx+1)/2),m_iKey) < 0 ) hidx = cidx-1;
|
|
else lidx = cidx;
|
|
return lidx;
|
|
}
|
|
|
|
template<class TYPE>
|
|
int CSTPArray<TYPE>::LowerBound(int idx)
|
|
{
|
|
int lidx, hidx, cidx;
|
|
if(idx<=0 || idx>GetUpperBound()) return 0; // the item is out of bounds or the last in the array
|
|
TYPE* pCrt = GetAt(lidx = hidx = idx); // this is the target
|
|
// if the first element of the array is <=> with the target, return its index (no use for further search)
|
|
if(!TYPE::Compare(pCrt,GetAt(0),m_iKey)) return 0;
|
|
// find the interval bound
|
|
for(lidx--; !TYPE::Compare(pCrt,GetAt(lidx),m_iKey); hidx = lidx, lidx = max(0,idx-(idx-lidx)*2));
|
|
lidx++;
|
|
while(hidx > lidx)
|
|
if(TYPE::Compare(pCrt,GetAt(cidx = (hidx+lidx)/2),m_iKey)>0) lidx = cidx+1;
|
|
else hidx = cidx;
|
|
return lidx;
|
|
}
|
|
|
|
#include "arrtempl.inl" // the CArray class
|
|
|
|
#endif
|