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.
589 lines
15 KiB
589 lines
15 KiB
/***************************************************************************\
|
|
*
|
|
* File: Array.inl
|
|
*
|
|
* History:
|
|
* 1/04/2000: JStall: Created
|
|
*
|
|
* Copyright (C) 2000 by Microsoft Corporation. All rights reserved.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
#if !defined(BASE__Array_inl__INCLUDED)
|
|
#define BASE__Array_inl__INCLUDED
|
|
|
|
#include "SimpleHeap.h"
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* class GArrayS
|
|
*
|
|
\***************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline
|
|
GArrayS<T, heap>::GArrayS() : m_aT(NULL)
|
|
{
|
|
//
|
|
// All elements in GArrayS<T, heap> must be at least sizeof(int) large. This is
|
|
// because of the design that stores the size in the element preceeding the
|
|
// data for the array.
|
|
//
|
|
|
|
AssertMsg(sizeof(T) >= sizeof(int), "Ensure minimum element size");
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline
|
|
GArrayS<T, heap>::~GArrayS()
|
|
{
|
|
RemoveAll();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
BOOL
|
|
GArrayS<T, heap>::IsEmpty() const
|
|
{
|
|
return m_aT == NULL;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline void *
|
|
GArrayS<T, heap>::GetRawData(BOOL fCheckNull) const
|
|
{
|
|
if (fCheckNull) {
|
|
//
|
|
// Need to check if array is allocated
|
|
//
|
|
|
|
if (m_aT != NULL) {
|
|
return (void *) (&m_aT[-1]);
|
|
} else {
|
|
return NULL;
|
|
}
|
|
} else {
|
|
//
|
|
// Blindly return the size
|
|
//
|
|
|
|
AssertMsg(m_aT != NULL, "Array must be allocated if not checking");
|
|
return &m_aT[-1];
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline void
|
|
GArrayS<T, heap>::SetRawSize(int cNewItems)
|
|
{
|
|
//
|
|
// Store the size before the array data. This function should only be
|
|
// called when an array is allocated (and thus have a non-zero size).
|
|
//
|
|
|
|
AssertMsg(cNewItems > 0, "Must specify a positive number of items");
|
|
AssertMsg(m_aT != NULL, "Must allocate range to set number of items");
|
|
|
|
int * pnSize = (int *) GetRawData(FALSE);
|
|
*pnSize = cNewItems;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline int
|
|
GArrayS<T, heap>::GetSize() const
|
|
{
|
|
if (m_aT != NULL) {
|
|
int * pnSize = (int *) GetRawData(FALSE);
|
|
int cItems = *pnSize;
|
|
AssertMsg(cItems >= 1, "Must have at least one item");
|
|
return cItems;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayS<T, heap>::SetSize(int cItems)
|
|
{
|
|
AssertMsg(cItems >= 0, "Must have valid size");
|
|
|
|
int cSize = GetSize();
|
|
if (cSize == cItems) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (cItems == 0) {
|
|
RemoveAll();
|
|
return TRUE;
|
|
} else {
|
|
return Resize(cItems, cSize);
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline int
|
|
GArrayS<T, heap>::Add(const T & t)
|
|
{
|
|
int idxAdd = GetSize();
|
|
if (!Resize(idxAdd + 1, idxAdd)) {
|
|
return -1;
|
|
}
|
|
|
|
SetAtIndex(idxAdd, t);
|
|
return idxAdd;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayS<T, heap>::InsertAt(int idxItem, const T & t)
|
|
{
|
|
AssertMsg(idxItem <= GetSize(), "Check index");
|
|
|
|
// Actually may need to increase the size by one and shift everything
|
|
// down
|
|
|
|
int idxAdd = GetSize();
|
|
if (!Resize(idxAdd + 1, idxAdd)) {
|
|
return FALSE;
|
|
}
|
|
|
|
int cbMove = (idxAdd - idxItem) * sizeof(T);
|
|
if (cbMove > 0) {
|
|
MoveMemory(&m_aT[idxItem + 1], &m_aT[idxItem], cbMove);
|
|
}
|
|
SetAtIndex(idxItem, t);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayS<T, heap>::Remove(const T & t)
|
|
{
|
|
int idxItem = Find(t);
|
|
if(idxItem == -1) {
|
|
return FALSE;
|
|
}
|
|
return RemoveAt(idxItem);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayS<T, heap>::RemoveAt(int idxItem)
|
|
{
|
|
int cItems = GetSize();
|
|
AssertMsg((idxItem < cItems) && (cItems >= 0), "Ensure valid index");
|
|
m_aT[idxItem].~T();
|
|
|
|
cItems--;
|
|
if (cItems > 0) {
|
|
//
|
|
// Found the element, so we need to splice it out of the array. We
|
|
// can not just Realloc() the buffer b/c we need to slide all
|
|
// property data after this down one. This means that we have to
|
|
// allocate a new buffer. If we are unable to allocate a temporary
|
|
// buffer, we can go ahead and just use the existing buffer, but we
|
|
// won't be able to free any memory.
|
|
//
|
|
|
|
if (idxItem < cItems) {
|
|
MoveMemory((void*)&m_aT[idxItem], (void*)&m_aT[idxItem + 1], (cItems - idxItem) * sizeof(T));
|
|
}
|
|
|
|
T * rgNewData = (T *) ContextRealloc(heap::GetHeap(), GetRawData(FALSE), (cItems + 1) * sizeof(T));
|
|
if (rgNewData != NULL) {
|
|
m_aT = &rgNewData[1];
|
|
}
|
|
|
|
SetRawSize(cItems);
|
|
} else {
|
|
ContextFree(heap::GetHeap(), GetRawData(FALSE));
|
|
m_aT = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline void
|
|
GArrayS<T, heap>::RemoveAll()
|
|
{
|
|
if(m_aT != NULL) {
|
|
int cItems = GetSize();
|
|
for(int i = 0; i < cItems; i++) {
|
|
m_aT[i].~T();
|
|
}
|
|
ContextFree(heap::GetHeap(), GetRawData(FALSE));
|
|
m_aT = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline T &
|
|
GArrayS<T, heap>::operator[] (int idxItem) const
|
|
{
|
|
Assert(idxItem >= 0 && idxItem < GetSize());
|
|
return m_aT[idxItem];
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline T *
|
|
GArrayS<T, heap>::GetData() const
|
|
{
|
|
return m_aT;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline void
|
|
GArrayS<T, heap>::SetAtIndex(int idxItem, const T & t)
|
|
{
|
|
Assert(idxItem >= 0 && (idxItem < GetSize()));
|
|
placement_copynew(&m_aT[idxItem], T, t);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline int
|
|
GArrayS<T, heap>::Find(const T & t) const
|
|
{
|
|
int cItems = GetSize();
|
|
for(int i = 0; i < cItems; i++) {
|
|
if(m_aT[i] == t) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1; // not found
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* GArrayS<T, heap>::Resize()
|
|
*
|
|
* Resize() changes the size of the array to a non-zero number of elements.
|
|
*
|
|
* NOTE: This function has been specifically written for the GArrayS<T, heap>
|
|
* class and has slightly different behavior that GArrayF<T, heap>::Resize().
|
|
*
|
|
\***************************************************************************/
|
|
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayS<T, heap>::Resize(
|
|
IN int cItems, // New number of items
|
|
IN int cSize) // Current size
|
|
{
|
|
AssertMsg(cItems > 0, "Must have non-zero and positive number of items");
|
|
AssertMsg(cItems != cSize, "Must have a different size");
|
|
|
|
if (cItems < cSize) {
|
|
//
|
|
// Making the array smaller, so need to destruct the objects we are
|
|
// getting rid of.
|
|
//
|
|
|
|
AssertMsg(m_aT != NULL, "Should have data allocated");
|
|
for(int i = cItems; i < cSize; i++) {
|
|
m_aT[i].~T();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resize the array and store the new size.
|
|
//
|
|
|
|
T * aT;
|
|
aT = (T *) ContextRealloc(heap::GetHeap(), GetRawData(TRUE), (cItems + 1) * sizeof(T));
|
|
if(aT == NULL) {
|
|
AssertMsg(cItems >= cSize, "Should never fail when shrinking");
|
|
return FALSE;
|
|
}
|
|
|
|
m_aT = &aT[1];
|
|
SetRawSize(cItems);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* class GArrayBase
|
|
*
|
|
\***************************************************************************/
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline
|
|
GArrayF<T, heap>::GArrayF() : m_aT(NULL), m_nSize(0), m_nAllocSize(0)
|
|
{
|
|
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline
|
|
GArrayF<T, heap>::~GArrayF()
|
|
{
|
|
RemoveAll();
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayF<T, heap>::IsEmpty() const
|
|
{
|
|
//
|
|
// GArrayF may have a non-NULL m_aT but a m_nSize if only Add() and Remove()
|
|
// are used, treating the array like a stack. Therefore, we must use
|
|
// m_nSize to determine if the array is "empty". To free all memory
|
|
// allocated by the array, use RemoveAll().
|
|
//
|
|
|
|
return m_nSize <= 0;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline int
|
|
GArrayF<T, heap>::GetSize() const
|
|
{
|
|
return m_nSize;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayF<T, heap>::SetSize(int cItems)
|
|
{
|
|
AssertMsg(cItems >= 0, "Must have valid size");
|
|
|
|
if (!Resize(cItems)) {
|
|
return FALSE;
|
|
}
|
|
|
|
m_nSize = cItems;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline int
|
|
GArrayF<T, heap>::Add(const T & t)
|
|
{
|
|
if(m_nSize == m_nAllocSize) {
|
|
int nNewAllocSize = (m_nAllocSize == 0) ? 8 : (m_nAllocSize * 2);
|
|
if (!Resize(nNewAllocSize)) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int idxAdd = m_nSize;
|
|
m_nSize++;
|
|
SetAtIndex(idxAdd, t);
|
|
return idxAdd;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayF<T, heap>::InsertAt(int idxItem, const T & t)
|
|
{
|
|
AssertMsg(idxItem <= m_nSize, "Check index");
|
|
|
|
// Actually may need to increase the size by one and shift everything
|
|
// down
|
|
|
|
if (!Resize(m_nSize + 1)) {
|
|
return FALSE;
|
|
}
|
|
|
|
int cbMove = (m_nSize - idxItem) * sizeof(T);
|
|
if (cbMove > 0) {
|
|
MoveMemory(&m_aT[idxItem + 1], &m_aT[idxItem], cbMove);
|
|
}
|
|
m_nSize++;
|
|
SetAtIndex(idxItem, t);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayF<T, heap>::Remove(const T & t)
|
|
{
|
|
int idxItem = Find(t);
|
|
if(idxItem == -1) {
|
|
return FALSE;
|
|
}
|
|
return RemoveAt(idxItem);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayF<T, heap>::RemoveAt(int idxItem)
|
|
{
|
|
AssertMsg((idxItem < m_nSize) && (idxItem >= 0), "Must specify a valid index");
|
|
|
|
if(idxItem != (m_nSize - 1)) {
|
|
m_aT[idxItem].~T();
|
|
MoveMemory((void*)&m_aT[idxItem], (void*)&m_aT[idxItem + 1], (m_nSize - (idxItem + 1)) * sizeof(T));
|
|
}
|
|
m_nSize--;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline void
|
|
GArrayF<T, heap>::RemoveAll()
|
|
{
|
|
if(m_aT != NULL) {
|
|
for(int i = 0; i < m_nSize; i++) {
|
|
m_aT[i].~T();
|
|
}
|
|
ContextFree(heap::GetHeap(), m_aT);
|
|
m_aT = NULL;
|
|
}
|
|
m_nSize = 0;
|
|
m_nAllocSize = 0;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline T &
|
|
GArrayF<T, heap>::operator[] (int idxItem) const
|
|
{
|
|
AssertMsg((idxItem < m_nSize) && (idxItem >= 0), "Must specify a valid index");
|
|
return m_aT[idxItem];
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline T *
|
|
GArrayF<T, heap>::GetData() const
|
|
{
|
|
return m_aT;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline void
|
|
GArrayF<T, heap>::SetAtIndex(int idxItem, const T & t)
|
|
{
|
|
AssertMsg((idxItem < m_nSize) && (idxItem >= 0), "Must specify a valid index");
|
|
placement_copynew(&m_aT[idxItem], T, t);
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <class T, class heap>
|
|
inline int
|
|
GArrayF<T, heap>::Find(const T & t) const
|
|
{
|
|
for(int i = 0; i < m_nSize; i++) {
|
|
if(m_aT[i] == t) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1; // not found
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* GArrayF<T, heap>::Resize()
|
|
*
|
|
* Resize() changes the size of the array.
|
|
*
|
|
* NOTE: This function has been specifically written for the GArrayF<T, heap>
|
|
* class and has slightly different behavior that GArrayS<T, heap>::Resize().
|
|
*
|
|
\***************************************************************************/
|
|
|
|
template <class T, class heap>
|
|
inline BOOL
|
|
GArrayF<T, heap>::Resize(int cItems)
|
|
{
|
|
if (cItems == 0) {
|
|
RemoveAll();
|
|
} else {
|
|
AssertMsg(m_nAllocSize >= m_nSize, "Ensure legal sizes");
|
|
|
|
if (cItems < m_nSize) {
|
|
//
|
|
// Making the array smaller, so need to destruct the objects we are
|
|
// getting rid of.
|
|
//
|
|
|
|
if(m_aT != NULL) {
|
|
for(int i = cItems; i < m_nSize; i++) {
|
|
m_aT[i].~T();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Resize the array, but don't update m_nSize b/c that is the caller's
|
|
// responsibility.
|
|
//
|
|
|
|
T * aT;
|
|
aT = (T *) ContextRealloc(heap::GetHeap(), m_aT, cItems * sizeof(T));
|
|
if(aT == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
m_nAllocSize = cItems;
|
|
m_aT = aT;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
#endif // BASE__Array_inl__INCLUDED
|