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.
335 lines
11 KiB
335 lines
11 KiB
/*==========================================================================
|
|
*
|
|
* Copyright (C) 1995 - 2000 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* File: OrderedArray.h
|
|
* Content: COrderedArray / COrderedPtrArray Declarations
|
|
*
|
|
* History:
|
|
* Date By Reason
|
|
* ====== == ======
|
|
* 12-12-2001 simonpow Created
|
|
***************************************************************************/
|
|
|
|
|
|
#ifndef __ORDEREDARRAY_H__
|
|
#define __ORDEREDARRAY_H__
|
|
|
|
#include "AutoArray.h"
|
|
|
|
/*
|
|
* COrderedArray
|
|
* Maintains an array of elements that can be inserted into and removed
|
|
* from whilst maintaining element order. i.e. List like semantics
|
|
* This class is useful when you want to maintain a list of items in
|
|
* order and scan the data far more often than you modify the list.
|
|
* If you perform lots of insert/remove operations, then a linked
|
|
* list is probably more efficient.
|
|
* Memory management is handled through CAutoArray so see comments
|
|
* in that header for more information
|
|
*
|
|
* If you need an array of pointers use the specialisation COrderedPtrArray
|
|
* declared below the COrderedArray class.
|
|
*/
|
|
|
|
|
|
template <class T > class COrderedArray
|
|
{
|
|
public:
|
|
|
|
//provides the type of entries held
|
|
typedef T Entry;
|
|
|
|
//array starts 0 zero and by default grows in multiples
|
|
//of 16 elements at a time
|
|
COrderedArray(DWORD dwSizeMultiple=16) : m_data(dwSizeMultiple), m_dwTopFreeSlot(0)
|
|
{ };
|
|
|
|
//standard d'tor
|
|
~COrderedArray()
|
|
{};
|
|
|
|
/*
|
|
* Memory Management
|
|
*/
|
|
|
|
//Delete existing contents and reset the size multiplier
|
|
//Pass 0 for size multiplier to retain the existing value
|
|
void Reset(DWORD dwSizeMultiple=16)
|
|
{ m_data.Reset(dwSizeMultiple); m_dwTopFreeSlot=0; };
|
|
|
|
//ensure that there is enough space in the array to hold at least
|
|
//'numElements' without needing to re-create and copy the data
|
|
//returns FALSE if fails due to memory allocation failure
|
|
BOOL AllocAtLeast(DWORD dwNumElements)
|
|
{ return m_data.AllocAtLeast(dwNumElements); };
|
|
|
|
//ensure there is enough space in the array to hold at least an
|
|
//extra 'numElements' without needing to re-create and copy the data
|
|
//returns FALSE if fails due to memory allocation failure
|
|
BOOL AllocExtra(DWORD dwNumElements)
|
|
{ return m_data.AllocAtLeast(dwNumElements+m_dwTopFreeSlot); };
|
|
|
|
|
|
/*
|
|
* Adding/Modifying Elements
|
|
*/
|
|
|
|
//add an entry to end of array
|
|
//returns FALSE if fails due to memory allocation failure
|
|
BOOL AddElement(const T& elem)
|
|
{ return m_data.SetElement(m_dwTopFreeSlot++, elem); };
|
|
|
|
//add a number of elements to the end of the array
|
|
//N.B. Don't pass pointers into data in this array as 'pElem'!
|
|
//e.g. Don't do array.AddElements(array.GetAllElements, array.GetNumElements());
|
|
//returns FALSE if fails due to memory allocation failure
|
|
BOOL AddElements(const T * pElem, DWORD dwNumElem);
|
|
|
|
//add the entries from another ordered array to the end of this one
|
|
//N.B. Don't pass array to itself (e.g. Don't do array.AddElements(array); )
|
|
//returns FALSE if fails due to memory allocation failure
|
|
BOOL AddElements(const COrderedArray<T>& array);
|
|
|
|
//set the element at 'dwIndex' to 'elem. Upto caller to
|
|
//ensure this doesn't create a hole in array (i.e. dwIndex must be<=Num Entries)
|
|
//returns FALSE if fails due to memory allocation failure
|
|
inline BOOL SetElement(DWORD dwIndex, const T& elem);
|
|
|
|
//set 'dwNumElem' from 'dwIndex' to values specified by 'pElem'
|
|
//Upto caller to ensure this doesn't create a hole in array
|
|
//(i.e. dwIndex must be<=Num Entries)
|
|
//N.B. Don't pass pointers into data in this array as 'pElem'!
|
|
//e.g. Don't do array.SetElements(x, array.GetAllElements, array.GetNumElements());
|
|
//returns FALSE if fails due to memory allocation failure
|
|
inline BOOL SetElements(DWORD dwIndex, const T * pElem, DWORD dwNumElem);
|
|
|
|
//insert element 'elem' at index 'dwIndex, shifting up
|
|
//elements after 'dwIndex' if necessary
|
|
//Upto caller to ensure this doesn't create a hole in the array
|
|
//i.e. dwIndex is within the current range
|
|
//returns FALSE if fails due to memory allocation failure
|
|
BOOL InsertElement(DWORD dwIndex, const T& elem);
|
|
|
|
//insert 'dwNumElem' elements pointed to be 'pElems' into array
|
|
//at index 'dwIndex', shifting up any existing elements if necessary
|
|
//Upto caller to ensure this doesn't create a hole in the array
|
|
//i.e. dwIndex is within the current range
|
|
//N.B. Don't pass pointers into data in this array as 'pElem'!
|
|
//e.g. Don't do array.InsertElements(x, array.GetAllElements, array.GetNumElements());
|
|
//returns FALSE if fails due to memory allocation failure
|
|
BOOL InsertElements(DWORD dwIndex, const T * pElems, DWORD dwNumElem);
|
|
|
|
|
|
/*
|
|
* Removing Entries
|
|
*/
|
|
|
|
//remove the single entry at 'dwIndex', shifting all the entries
|
|
//between 'index'+1 and the last entry down by one.
|
|
//Upto caller to ensure dwIndex falls within the current array range
|
|
inline void RemoveElementByIndex(DWORD dwIndex);
|
|
|
|
//remove a block of 'dwNumElem' elements starting at 'dwIndex', moving
|
|
//down all entries between 'index'+1 and the last entry by 'dwNumElem'.
|
|
//Upto caller to ensure specified block falls within the current array range
|
|
inline void RemoveElementsByIndex(DWORD dwIndex, DWORD dwNumElem);
|
|
|
|
//remove first entry in array that matches 'elem'
|
|
//returns TRUE if a match is found and FALSE otherwise
|
|
BOOL RemoveElementByValue(const T& elem);
|
|
|
|
//remove all the current entries in the array
|
|
void RemoveAll()
|
|
{ m_dwTopFreeSlot=0; };
|
|
|
|
|
|
/*
|
|
* Accessing the array data
|
|
* N.B. Treat any pointers into array contents very carefully.
|
|
* Adding new elements to the array or using the Alloc* methods
|
|
* can cause them to become invalid
|
|
*/
|
|
|
|
//returns the number of entries
|
|
DWORD GetNumElements() const
|
|
{ return m_dwTopFreeSlot; };
|
|
|
|
//returns TRUE if array is empty
|
|
BOOL IsEmpty() const
|
|
{ return (m_dwTopFreeSlot==0); };
|
|
|
|
//return value at a specific index
|
|
T GetElementValue(DWORD dwIndex) const
|
|
{ return m_data.GetElementValue(dwIndex); };
|
|
|
|
//return reference to an element at specific index
|
|
T& GetElementRef(DWORD dwIndex)
|
|
{ return m_data.GetElementRef(dwIndex); };
|
|
|
|
//return constant reference to an element at specific index
|
|
const T& GetElementRef(DWORD dwIndex) const
|
|
{ return m_data.GetElementRef(dwIndex); };
|
|
|
|
//return a pointer to an element
|
|
T * GetElementPtr(DWORD dwIndex)
|
|
{ return m_data.GetElementPtr(dwIndex); };
|
|
|
|
//returns pointer to array of all elements
|
|
T * GetAllElements()
|
|
{ return m_data.GetAllElements(); };
|
|
|
|
/*
|
|
* Searching Array
|
|
*/
|
|
|
|
//find an instance of 'elem' in array. If found returns TRUE
|
|
//and sets 'pdwIndex' to index of element
|
|
BOOL FindElement(const T& elem, DWORD * pdwIndex) const;
|
|
|
|
//returns TRUE if 'elem' is present in bag
|
|
BOOL IsElementPresent(const T& elem) const
|
|
{ DWORD dwIndex; return (FindElement(elem, &dwIndex)); };
|
|
|
|
protected:
|
|
|
|
|
|
CAutoArray<T> m_data;
|
|
DWORD m_dwTopFreeSlot;
|
|
|
|
};
|
|
|
|
/*
|
|
* Specialisation of COrderedArray for handling pointers
|
|
* If you ever need to declare an ordered array of pointers (e.g. char *)
|
|
* declare it as an COrderedPtrArray (e.g. COrderedPtrArray<char *>).
|
|
* This specilisation uses a COrderedArray<void *> underneath and hence
|
|
* re-uses the same code between all types of COrderedPtrArray.
|
|
*/
|
|
|
|
template <class T> class COrderedPtrArray : public COrderedArray<void * >
|
|
{
|
|
public:
|
|
|
|
typedef T Entry;
|
|
|
|
typedef COrderedArray<void * > Base;
|
|
|
|
COrderedPtrArray(DWORD dwSizeMultiple=16) : COrderedArray<void*>(dwSizeMultiple)
|
|
{ };
|
|
|
|
BOOL AddElement(T elem)
|
|
{ return Base::AddElement((void * ) elem); };
|
|
|
|
BOOL AddElements(const T * pElem, DWORD dwNumElem)
|
|
{ return Base::AddElements((void **) pElem, dwNumElem); };
|
|
|
|
BOOL AddElements(const COrderedArray<T>& array)
|
|
{ return Base::AddElements((COrderedArray<void*>&) array); };
|
|
|
|
BOOL SetElement(DWORD dwIndex, T elem)
|
|
{ return Base::SetElement(dwIndex, (void * ) elem); };
|
|
|
|
BOOL SetElements(DWORD dwIndex, T * pElem, DWORD dwNumElem)
|
|
{ return Base::SetElements(dwIndex, (void**) pElem, dwNumElem); };
|
|
|
|
BOOL InsertElement(DWORD dwIndex, T elem)
|
|
{ return Base::InsertElement(dwIndex, (void * ) elem); };
|
|
|
|
BOOL InsertElements(DWORD dwIndex, const T * pElems, DWORD dwNumElem)
|
|
{ return Base::InsertElements(dwIndex, (void **) pElems, dwNumElem); };
|
|
|
|
BOOL RemoveElementByValue(T elem)
|
|
{ return Base::RemoveElementByValue((void *) elem); };
|
|
|
|
T GetElementValue(DWORD dwIndex) const
|
|
{ return (T) m_data.GetElementValue(dwIndex); };
|
|
|
|
T& GetElementRef(DWORD dwIndex)
|
|
{ return (T&) m_data.GetElementRef(dwIndex); };
|
|
const T& GetElementRef(DWORD dwIndex) const
|
|
{ return (const T&) m_data.GetElementRef(dwIndex); };
|
|
|
|
T * GetElementPtr(DWORD dwIndex)
|
|
{ return (T*) m_data.GetElementPtr(dwIndex); };
|
|
|
|
T * GetAllElements()
|
|
{ return (T*) m_data.GetAllElements(); };
|
|
|
|
BOOL FindElement(T elem, DWORD * pdwIndex) const
|
|
{ return Base::FindElement((void * ) elem, pdwIndex); };
|
|
|
|
BOOL IsElementPresent(T elem) const
|
|
{ DWORD dwIndex; return (Base::FindElement((void * ) elem, &dwIndex)); };
|
|
};
|
|
|
|
/*
|
|
* COrderedArray inline methods
|
|
*/
|
|
|
|
template <class T>
|
|
BOOL COrderedArray<T>::AddElements(const T * pElem, DWORD dwNumElem)
|
|
{
|
|
//ensure pointer passed isn't into this arrays contents
|
|
DNASSERT(!(pElem>=m_data.GetAllElements() && pElem<m_data.GetAllElements()+m_data.GetCurrentSize()));
|
|
if (!m_data.AllocAtLeast(m_dwTopFreeSlot+dwNumElem))
|
|
return FALSE;
|
|
m_data.SetExistingElements(m_dwTopFreeSlot, pElem, dwNumElem);
|
|
m_dwTopFreeSlot+=dwNumElem;
|
|
return TRUE;
|
|
}
|
|
|
|
template <class T>
|
|
BOOL COrderedArray<T>::SetElement(DWORD dwIndex, const T& elem)
|
|
{
|
|
DNASSERT(dwIndex<=m_dwTopFreeSlot);
|
|
if (dwIndex==m_dwTopFreeSlot)
|
|
return m_data.SetElement(m_dwTopFreeSlot++, elem);
|
|
m_data.SetExistingElement(dwIndex, elem);
|
|
return TRUE;
|
|
}
|
|
|
|
template <class T>
|
|
BOOL COrderedArray<T>::SetElements(DWORD dwIndex, const T * pElem, DWORD dwNumElem)
|
|
{
|
|
//ensure pointer passed isn't into this arrays contents
|
|
DNASSERT(!(pElem>=m_data.GetAllElements() && pElem<m_data.GetAllElements()+m_data.GetCurrentSize()));
|
|
//ensure hole isn't created
|
|
DNASSERT(dwIndex<=m_dwTopFreeSlot);
|
|
if (!m_data.SetElements(dwIndex, pElem, dwNumElem))
|
|
return FALSE;
|
|
dwIndex+=dwNumElem;
|
|
m_dwTopFreeSlot = dwIndex>m_dwTopFreeSlot ? dwIndex : m_dwTopFreeSlot;
|
|
return TRUE;
|
|
}
|
|
|
|
template <class T>
|
|
void COrderedArray<T>::RemoveElementByIndex(DWORD dwIndex)
|
|
{
|
|
DNASSERT(dwIndex<m_dwTopFreeSlot);
|
|
m_data.MoveElements(dwIndex+1, m_dwTopFreeSlot-dwIndex-1, dwIndex, FALSE);
|
|
m_dwTopFreeSlot--;
|
|
};
|
|
|
|
template <class T>
|
|
void COrderedArray<T>::RemoveElementsByIndex(DWORD dwIndex, DWORD dwNumElem)
|
|
{
|
|
DNASSERT(dwIndex+dwNumElem<=m_dwTopFreeSlot);
|
|
m_data.MoveElements(dwIndex+dwNumElem, m_dwTopFreeSlot-dwIndex-dwNumElem, dwIndex, FALSE);
|
|
m_dwTopFreeSlot-=dwNumElem;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* If not building with explicit template instantiation then also
|
|
* include all other methods for COrderedArray
|
|
*/
|
|
|
|
#ifndef DPNBUILD_EXPLICIT_TEMPLATES
|
|
#include "OrderedArray.inl"
|
|
#endif
|
|
|
|
|
|
#endif //#ifndef __ORDEREDARRAY_H__
|
|
|