596 lines
11 KiB
C++
596 lines
11 KiB
C++
#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
|
|
|