|
|
#ifndef _INC_DSKQUOTA_CARRAY_H
#define _INC_DSKQUOTA_CARRAY_H
///////////////////////////////////////////////////////////////////////////////
/* File: carray.h
Description: Template class CArray. Implements a dynamic array class.
Much of the functionality is based on the feature set of MFC's CArray class.
Revision History:
Date Description Programmer -------- --------------------------------------------------- ---------- 09/16/97 Initial creation. BrianAu 12/13/97 Changed SetAtGrow to return true/false. True means BrianAu had to grow array. */ ///////////////////////////////////////////////////////////////////////////////
#ifndef _INC_DSKQUOTA_DEBUG_H
# include "debug.h"
#endif
#ifndef _INC_DSKQUOTA_THDSYNC_H
# include "thdsync.h"
#endif
#ifndef _INC_DSKQUOTA_EXCEPT_H
# include "except.h"
#endif
template <class T> class CArray { public: CArray<T>(VOID); explicit CArray<T>(INT cItems); CArray<T>(const CArray<T>& rhs); CArray<T>& operator = (const CArray<T>& rhs);
virtual ~CArray<T>(VOID);
VOID SetAt(const T& item, INT i); bool SetAtGrow(const T& item, INT i); T GetAt(INT i) const; VOID Insert(const T& item, INT i = -1); VOID Append(const T& item, INT i = -1); INT Find(const T& key); VOID Delete(INT i);
T operator [] (INT i) const; T& operator [] (INT i);
VOID Clear(VOID);
BOOL IsEmpty(VOID) const { return 0 == m_cItems; }
INT Count(VOID) const { return m_cItems; }
INT UpperBound(VOID) const { return m_cItems - 1; }
INT Size(VOID) const { return m_cAlloc; }
VOID SetGrow(INT cGrow) { m_cGrow = cGrow; }
VOID Copy(const CArray<T>& rhs);
VOID Append(const CArray<T>& rhs);
VOID SetSize(INT cEntries, INT iShift = -1);
VOID Lock(VOID) { m_cs.Enter(); }
VOID ReleaseLock(VOID) { m_cs.Leave(); }
protected: static INT DEFGROW; // Default growth value.
private: INT m_cAlloc; // Number of entry allocations.
INT m_cItems; // Number of used entries.
INT m_cGrow; T *m_rgItems; // Array of entries.
mutable CCriticalSection m_cs; // For multi-threaded access.
template <class U> const U& MIN(const U& a, const U& b) const { return a < b ? a : b; }
template <class U> const U& MAX(const U& a, const U& b) const { return a > b ? a : b; } };
template <class T> INT CArray<T>::DEFGROW = 8;
template <class T> CArray<T>::CArray( void ) : m_cAlloc(0), m_cItems(0), m_cGrow(DEFGROW), m_rgItems(NULL) {
}
template <class T> CArray<T>::CArray( INT cItems ) : m_cAlloc(0), m_cItems(0), m_cGrow(DEFGROW), m_rgItems(NULL) { SetSize(cItems); m_cItems = cItems; }
template <class T> CArray<T>::CArray( const CArray& rhs ) : m_cAlloc(0), m_cItems(0), m_cGrow(DEFGROW), m_rgItems(NULL) { *this = rhs; }
template <class T> VOID CArray<T>::Copy( const CArray<T>& rhs ) { AutoLockCs lock1(rhs.m_cs); AutoLockCs lock2(m_cs);
//
// Place *this in an empty state in case Grow() throws an exception.
// It should still be a valid CArray object.
//
delete[] m_rgItems; m_rgItems = NULL; m_cAlloc = 0; m_cItems = 0;
//
// Size the object to hold the source array.
//
SetSize(rhs.m_cAlloc);
//
// Copy the contents.
//
DBGASSERT((m_cAlloc >= rhs.m_cItems)); for (m_cItems = 0; m_cItems < rhs.m_cItems; m_cItems++) { //
// This assignment could throw an exception so only update
// our item count after each successful copy.
//
DBGASSERT((m_cItems < m_cAlloc)); m_rgItems[m_cItems] = rhs.m_rgItems[m_cItems]; } }
template <class T> VOID CArray<T>::Append( const CArray<T>& rhs ) { AutoLockCs lock1(rhs.m_cs); AutoLockCs lock2(m_cs);
//
// Size the object to hold both arrays.
//
SetSize(m_cAlloc + rhs.m_cItems);
//
// Append the contents.
//
DBGASSERT((m_cAlloc >= (m_cItems + rhs.m_cItems))); for (int i = 0; i < rhs.m_cItems; i++) { DBGASSERT((m_cItems < m_cAlloc)); m_rgItems[m_cItems++] = rhs.m_rgItems[i]; } }
template <class T> CArray<T>& CArray<T>::operator = ( const CArray<T>& rhs ) { if (this != &rhs) { Copy(rhs); } return *this; }
template <class T> CArray<T>::~CArray( VOID ) { Clear(); }
template <class T> T CArray<T>::operator [] ( INT i ) const { return GetAt(i); }
template <class T> T& CArray<T>::operator [] ( INT i ) { AutoLockCs lock(m_cs);
if (i < 0 || i >= m_cItems) throw CMemoryException(CMemoryException::index);
return *(m_rgItems + i); }
template <class T> VOID CArray<T>::Clear( VOID ) { AutoLockCs lock(m_cs); delete[] m_rgItems; m_rgItems = NULL; m_cAlloc = 0; m_cItems = 0; }
template <class T> VOID CArray<T>::Insert( const T& item, INT i ) { AutoLockCs lock(m_cs);
if (-1 == i) { //
// Insert at head of array.
//
i = 0; } //
// Can only insert an item before an existing item.
// i cannot be negative.
// If array is empty, i can only be 0.
// If array is not empty, i must be index of a valid item.
//
if ((0 == m_cItems && 0 != i) || (0 != m_cItems && (i < 0 || i >= m_cItems))) { throw CMemoryException(CMemoryException::index); }
DBGASSERT((m_cItems <= m_cAlloc)); if (m_cItems >= m_cAlloc) { //
// Grow the array if necessary.
// This will also shift the elements, beginning with element 'i',
// one element to the right.
//
SetSize(m_cAlloc + m_cGrow, i); } else { //
// Growth not necessary.
// Shift the contents of the array following the insertion point
// one element to the right.
//
for (int j = m_cItems; j > i; j--) { m_rgItems[j] = m_rgItems[j-1]; } } //
// We've now inserted an item.
//
m_cItems++; //
// Set the value at the inserted location.
// This assignment could throw an exception.
//
SetAt(item, i); }
template <class T> VOID CArray<T>::Append( const T& item, INT i ) { AutoLockCs lock(m_cs);
if (-1 == i) { //
// Append at end of array.
//
i = m_cItems - 1; } //
// Can only append an item after an existing item.
// When array is empty, i can only be -1.
// When array is not empty, i must be index of a valid item.
//
// Note: i will be -1 when m_cItems is 0.
//
if ((0 == m_cItems && -1 != i) || (0 != m_cItems && (i < 0 || i >= m_cItems))) { throw CMemoryException(CMemoryException::index); }
DBGASSERT((m_cItems <= m_cAlloc)); if (m_cItems >= m_cAlloc) { //
// Grow the array if necessary.
// This will also shift the elements, beginning with element 'i + 1',
// one element to the right.
//
SetSize(m_cAlloc + m_cGrow, i+1); } else { //
// Shift the contents of the array following the insertion
// point, one entry to the right.
//
for (int j = m_cItems; j > (i+1); j--) { m_rgItems[j] = m_rgItems[j-1]; } } //
// We've now appended an item.
//
m_cItems++; //
// Set the value at the appended location.
// This assignment could throw an exception.
//
SetAt(item, i+1); }
template <class T> VOID CArray<T>::Delete( INT i ) { AutoLockCs lock(m_cs);
//
// Can only delete a valid item.
//
if (i < 0 || i >= m_cItems) throw CMemoryException(CMemoryException::index); //
// Shift memory to remove the item.
//
for (int j = i; j < (m_cItems - 1); j++) { m_rgItems[j] = m_rgItems[j+1]; } //
// Now we have one less item.
//
m_cItems--; //
// Shrink the array if it's required size is less than 2X the
// array's "growth" amount.
//
if ((m_cAlloc - m_cItems) > (2 * m_cGrow)) { SetSize(m_cItems); } }
template <class T> INT CArray<T>::Find( const T& key ) { AutoLockCs lock(m_cs);
for (INT i = 0; i < m_cItems; i++) { if (m_rgItems[i] == key) { return i; } } return -1; }
template <class T> T CArray<T>::GetAt( INT i ) const { AutoLockCs lock(m_cs);
if (i < 0 || i >= m_cItems) throw CMemoryException(CMemoryException::index);
return m_rgItems[i]; }
template <class T> VOID CArray<T>::SetAt( const T& item, INT i ) { AutoLockCs lock(m_cs);
if (i < 0 || i >= m_cAlloc) throw CMemoryException(CMemoryException::index);
m_rgItems[i] = item; }
//
// Returns: true = array was extended, false = no extension required.
//
template <class T> bool CArray<T>::SetAtGrow( const T& item, INT i ) { bool bGrow = false; AutoLockCs lock(m_cs);
if (i >= m_cAlloc) { //
// Need to grow the array to accomodate the new item.
//
SetSize(i + m_cGrow); bGrow = true; } //
// Set the new item value.
//
SetAt(item, i); //
// Extend the count of "valid" items.
//
m_cItems = i + 1;
return bGrow; }
template <class T> VOID CArray<T>::SetSize( INT cEntries, INT iShift // Pass -1 for "no shift".
) { AutoLockCs lock(m_cs);
//
// Don't allow an array of less than 1 element.
//
cEntries = MAX(1, cEntries);
T *pNew = new T[cEntries]; if (NULL == pNew) throw CAllocException();
if (NULL != m_rgItems) { INT cCopy = MIN(cEntries, m_cItems); INT j = 0; for (INT i = 0; i < cCopy; i++, j++) { //
// Shift items [i..(n-1)] to [(i+1)..n]
//
if (iShift == j) j++;
*(pNew + j) = m_rgItems[i]; } } delete[] m_rgItems; m_rgItems = pNew; m_cAlloc = cEntries; }
template <class T> class CQueueAsArray : public CArray<T> { public: CQueueAsArray<T>(VOID) { } ~CQueueAsArray<T>(VOID) { }
VOID Add(T& item); BOOL Remove(T& item);
private: CQueueAsArray<T>(const CQueueAsArray<T>& rhs); CQueueAsArray<T>& operator = (const CQueueAsArray<T>& rhs);
};
template <class T> VOID CQueueAsArray<T>::Add( T& item ) { Append(item); }
template <class T> BOOL CQueueAsArray<T>::Remove( T& item ) { BOOL bResult = FALSE; if (!IsEmpty()) { INT i = UpperBound(); item = GetAt(i); Delete(i); bResult = TRUE; } return bResult; }
#endif // _INC_DSKQUOTA_CARRAY_H
|