📄 spcollec.h
字号:
/*****************************************************************************
* SPCollec.h *
*------------*
* This header file contains the SAPI5 collection class templates. These
* are a modified version of the MFC template classes without the dependencies.
*-----------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
*****************************************************************************/
#ifndef SPCollec_h
#define SPCollec_h
#ifndef _INC_LIMITS
#include <limits.h>
#endif
#ifndef _INC_STRING
#include <string.h>
#endif
#ifndef _INC_STDLIB
#include <stdlib.h>
#endif
#ifndef _WIN32_WCE
#ifndef _INC_SEARCH
#include <search.h>
#endif
#endif
/////////////////////////////////////////////////////////////////////////////
#define SPASSERT_VALID( a ) // This doesn't do anything right now
typedef void* SPLISTPOS;
typedef DWORD SPLISTHANDLE;
#define SP_BEFORE_START_POSITION ((void*)-1L)
inline BOOL SPIsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite)
{
// simple version using Win-32 APIs for pointer validation.
return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
(!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
}
/////////////////////////////////////////////////////////////////////////////
// global helpers (can be overridden)
template<class TYPE>
inline HRESULT SPConstructElements(TYPE* pElements, int nCount)
{
HRESULT hr = S_OK;
SPDBG_ASSERT( nCount == 0 ||
SPIsValidAddress( pElements, nCount * sizeof(TYPE), TRUE ) );
// default is bit-wise zero initialization
memset((void*)pElements, 0, nCount * sizeof(TYPE));
return hr;
}
template<class TYPE>
inline void SPDestructElements(TYPE* pElements, int nCount)
{
SPDBG_ASSERT( ( nCount == 0 ||
SPIsValidAddress( pElements, nCount * sizeof(TYPE), TRUE ) ) );
pElements; // not used
nCount; // not used
// default does nothing
}
template<class TYPE>
inline HRESULT SPCopyElements(TYPE* pDest, const TYPE* pSrc, int nCount)
{
HRESULT hr = S_OK;
SPDBG_ASSERT( ( nCount == 0 ||
SPIsValidAddress( pDest, nCount * sizeof(TYPE), TRUE )) );
SPDBG_ASSERT( ( nCount == 0 ||
SPIsValidAddress( pSrc, nCount * sizeof(TYPE), FALSE )) );
// default is bit-wise copy
memcpy(pDest, pSrc, nCount * sizeof(TYPE));
return hr;
}
template<class TYPE, class ARG_TYPE>
BOOL SPCompareElements(const TYPE* pElement1, const ARG_TYPE* pElement2)
{
SPDBG_ASSERT( SPIsValidAddress( pElement1, sizeof(TYPE), FALSE ) );
SPDBG_ASSERT( SPIsValidAddress( pElement2, sizeof(ARG_TYPE), FALSE ) );
return *pElement1 == *pElement2;
}
template<class ARG_KEY>
inline UINT SPHashKey(ARG_KEY key)
{
// default identity hash - works for most primitive values
return ((UINT)(void*)(DWORD)key) >> 4;
}
/////////////////////////////////////////////////////////////////////////////
// CSPPlex
struct CSPPlex // warning variable length structure
{
CSPPlex* pNext;
UINT nMax;
UINT nCur;
/* BYTE data[maxNum*elementSize]; */
void* data() { return this+1; }
static CSPPlex* PASCAL Create( CSPPlex*& pHead, UINT nMax, UINT cbElement )
{
CSPPlex* p = (CSPPlex*) new BYTE[sizeof(CSPPlex) + nMax * cbElement];
SPDBG_ASSERT(p);
p->nMax = nMax;
p->nCur = 0;
p->pNext = pHead;
pHead = p; // change head (adds in reverse order for simplicity)
return p;
}
void FreeDataChain()
{
CSPPlex* p = this;
while (p != NULL)
{
BYTE* bytes = (BYTE*) p;
CSPPlex* pNext = p->pNext;
delete[] bytes;
p = pNext;
}
}
};
/////////////////////////////////////////////////////////////////////////////
// CSPArray<TYPE, ARG_TYPE>
template<class TYPE, class ARG_TYPE>
class CSPArray
{
public:
// Construction
CSPArray();
// Attributes
int GetSize() const;
int GetUpperBound() const;
HRESULT SetSize(int nNewSize, int nGrowBy = -1);
// Operations
// Clean up
void FreeExtra();
void RemoveAll();
// Accessing elements
TYPE GetAt(int nIndex) const;
void SetAt(int nIndex, ARG_TYPE newElement);
TYPE& ElementAt(int nIndex);
// Direct Access to the element data (may return NULL)
const TYPE* GetData() const;
TYPE* GetData();
// Potentially growing the array
HRESULT SetAtGrow(int nIndex, ARG_TYPE newElement);
int Add(ARG_TYPE newElement);
int Append(const CSPArray& src);
HRESULT Copy(const CSPArray& src);
// overloaded operator helpers
TYPE operator[](int nIndex) const;
TYPE& operator[](int nIndex);
// Operations that move elements around
HRESULT InsertAt(int nIndex, ARG_TYPE newElement, int nCount = 1);
void RemoveAt(int nIndex, int nCount = 1);
HRESULT InsertAt(int nStartIndex, CSPArray* pNewArray);
void Sort(int (__cdecl *compare )(const void *elem1, const void *elem2 ));
// Implementation
protected:
TYPE* 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:
~CSPArray();
#ifdef _DEBUG
// void Dump(CDumpContext&) const;
void AssertValid() const;
#endif
};
/////////////////////////////////////////////////////////////////////////////
// CSPArray<TYPE, ARG_TYPE> inline functions
template<class TYPE, class ARG_TYPE>
inline int CSPArray<TYPE, ARG_TYPE>::GetSize() const
{ return m_nSize; }
template<class TYPE, class ARG_TYPE>
inline int CSPArray<TYPE, ARG_TYPE>::GetUpperBound() const
{ return m_nSize-1; }
template<class TYPE, class ARG_TYPE>
inline void CSPArray<TYPE, ARG_TYPE>::RemoveAll()
{ SetSize(0, -1); }
template<class TYPE, class ARG_TYPE>
inline TYPE CSPArray<TYPE, ARG_TYPE>::GetAt(int nIndex) const
{ SPDBG_ASSERT( (nIndex >= 0 && nIndex < m_nSize) );
return m_pData[nIndex]; }
template<class TYPE, class ARG_TYPE>
inline void CSPArray<TYPE, ARG_TYPE>::SetAt(int nIndex, ARG_TYPE newElement)
{ SPDBG_ASSERT( (nIndex >= 0 && nIndex < m_nSize) );
m_pData[nIndex] = newElement; }
template<class TYPE, class ARG_TYPE>
inline TYPE& CSPArray<TYPE, ARG_TYPE>::ElementAt(int nIndex)
{ SPDBG_ASSERT( (nIndex >= 0 && nIndex < m_nSize) );
return m_pData[nIndex]; }
template<class TYPE, class ARG_TYPE>
inline const TYPE* CSPArray<TYPE, ARG_TYPE>::GetData() const
{ return (const TYPE*)m_pData; }
template<class TYPE, class ARG_TYPE>
inline TYPE* CSPArray<TYPE, ARG_TYPE>::GetData()
{ return (TYPE*)m_pData; }
template<class TYPE, class ARG_TYPE>
inline int CSPArray<TYPE, ARG_TYPE>::Add(ARG_TYPE newElement)
{ int nIndex = m_nSize;
SetAtGrow(nIndex, newElement);
return nIndex; }
template<class TYPE, class ARG_TYPE>
inline TYPE CSPArray<TYPE, ARG_TYPE>::operator[](int nIndex) const
{ return GetAt(nIndex); }
template<class TYPE, class ARG_TYPE>
inline TYPE& CSPArray<TYPE, ARG_TYPE>::operator[](int nIndex)
{ return ElementAt(nIndex); }
/////////////////////////////////////////////////////////////////////////////
// CSPArray<TYPE, ARG_TYPE> out-of-line functions
template<class TYPE, class ARG_TYPE>
CSPArray<TYPE, ARG_TYPE>::CSPArray()
{
m_pData = NULL;
m_nSize = m_nMaxSize = m_nGrowBy = 0;
}
template<class TYPE, class ARG_TYPE>
CSPArray<TYPE, ARG_TYPE>::~CSPArray()
{
SPASSERT_VALID( this );
if (m_pData != NULL)
{
SPDestructElements(m_pData, m_nSize);
delete[] (BYTE*)m_pData;
}
}
template<class TYPE, class ARG_TYPE>
HRESULT CSPArray<TYPE, ARG_TYPE>::SetSize(int nNewSize, int nGrowBy)
{
SPASSERT_VALID( this );
SPDBG_ASSERT( nNewSize >= 0 );
HRESULT hr = S_OK;
if (nGrowBy != -1)
m_nGrowBy = nGrowBy; // set new size
if (nNewSize == 0)
{
// shrink to nothing
if (m_pData != NULL)
{
SPDestructElements(m_pData, m_nSize);
delete[] (BYTE*)m_pData;
m_pData = NULL;
}
m_nSize = m_nMaxSize = 0;
}
else if (m_pData == NULL)
{
// create one with exact size
#ifdef SIZE_T_MAX
SPDBG_ASSERT( nNewSize <= SIZE_T_MAX/sizeof(TYPE) ); // no overflow
#endif
m_pData = (TYPE*) new BYTE[nNewSize * sizeof(TYPE)];
if( m_pData )
{
hr = SPConstructElements(m_pData, nNewSize);
if( SUCCEEDED( hr ) )
{
m_nSize = m_nMaxSize = nNewSize;
}
else
{
delete[] (BYTE*)m_pData;
m_pData = NULL;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
else if (nNewSize <= m_nMaxSize)
{
// it fits
if (nNewSize > m_nSize)
{
// initialize the new elements
hr = SPConstructElements(&m_pData[m_nSize], nNewSize-m_nSize);
}
else if (m_nSize > nNewSize)
{
// destroy the old elements
SPDestructElements(&m_pData[nNewSize], m_nSize-nNewSize);
}
if( SUCCEEDED( hr ) )
{
m_nSize = nNewSize;
}
}
else
{
// otherwise, grow array
int nGrowBy = m_nGrowBy;
if (nGrowBy == 0)
{
// heuristically determe growth when nGrowBy == 0
// (this avoids heap fragmentation in many situations)
nGrowBy = min(1024, max(4, m_nSize / 8));
}
int nNewMax;
if (nNewSize < m_nMaxSize + nGrowBy)
nNewMax = m_nMaxSize + nGrowBy; // granularity
else
nNewMax = nNewSize; // no slush
SPDBG_ASSERT( nNewMax >= m_nMaxSize ); // no wrap around
#ifdef SIZE_T_MAX
SPDBG_ASSERT( nNewMax <= SIZE_T_MAX/sizeof(TYPE) ); // no overflow
#endif
TYPE* pNewData = (TYPE*) new BYTE[nNewMax * sizeof(TYPE)];
if( pNewData )
{
// copy new data from old
memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
// construct remaining elements
SPDBG_ASSERT( nNewSize > m_nSize );
hr = SPConstructElements(&pNewData[m_nSize], nNewSize-m_nSize);
// get rid of old stuff (note: no destructors called)
delete[] (BYTE*)m_pData;
m_pData = pNewData;
m_nSize = nNewSize;
m_nMaxSize = nNewMax;
}
else
{
hr = E_OUTOFMEMORY;
}
}
return hr;
}
template<class TYPE, class ARG_TYPE>
int CSPArray<TYPE, ARG_TYPE>::Append(const CSPArray& src)
{
SPASSERT_VALID( this );
SPDBG_ASSERT( this != &src ); // cannot append to itself
int nOldSize = m_nSize;
HRESULT hr = SetSize(m_nSize + src.m_nSize);
if( SUCCEEDED( hr ) )
{
hr = SPCopyElements(m_pData + nOldSize, src.m_pData, src.m_nSize);
}
return ( SUCCEEDED( hr ) )?(nOldSize):(-1);
}
template<class TYPE, class ARG_TYPE>
HRESULT CSPArray<TYPE, ARG_TYPE>::Copy(const CSPArray& src)
{
SPASSERT_VALID( this );
SPDBG_ASSERT( this != &src ); // cannot copy to itself
HRESULT hr = SetSize(src.m_nSize);
if( SUCCEEDED( hr ) )
{
hr = SPCopyElements(m_pData, src.m_pData, src.m_nSize);
}
return hr;
}
template<class TYPE, class ARG_TYPE>
void CSPArray<TYPE, ARG_TYPE>::FreeExtra()
{
SPASSERT_VALID( this );
if (m_nSize != m_nMaxSize)
{
// shrink to desired size
#ifdef SIZE_T_MAX
SPDBG_ASSERT( m_nSize <= SIZE_T_MAX/sizeof(TYPE)); // no overflow
#endif
TYPE* pNewData = NULL;
if (m_nSize != 0)
{
pNewData = (TYPE*) new BYTE[m_nSize * sizeof(TYPE)];
SPDBG_ASSERT(pNewData);
// copy new data from old
memcpy(pNewData, m_pData, m_nSize * sizeof(TYPE));
}
// get rid of old stuff (note: no destructors called)
delete[] (BYTE*)m_pData;
m_pData = pNewData;
m_nMaxSize = m_nSize;
}
}
template<class TYPE, class ARG_TYPE>
HRESULT CSPArray<TYPE, ARG_TYPE>::SetAtGrow(int nIndex, ARG_TYPE newElement)
{
SPASSERT_VALID( this );
SPDBG_ASSERT( nIndex >= 0 );
HRESULT hr = S_OK;
if (nIndex >= m_nSize)
{
hr = SetSize(nIndex+1, -1);
}
if( SUCCEEDED( hr ) )
{
m_pData[nIndex] = newElement;
}
return hr;
}
template<class TYPE, class ARG_TYPE>
HRESULT CSPArray<TYPE, ARG_TYPE>::InsertAt(int nIndex, ARG_TYPE newElement, int nCount /*=1*/)
{
SPASSERT_VALID( this );
SPDBG_ASSERT( nIndex >= 0 ); // will expand to meet need
SPDBG_ASSERT( nCount > 0 ); // zero or negative size not allowed
HRESULT hr = S_OK;
if (nIndex >= m_nSize)
{
// adding after the end of the array
hr = SetSize(nIndex + nCount, -1); // grow so nIndex is valid
}
else
{
// inserting in the middle of the array
int nOldSize = m_nSize;
hr = SetSize(m_nSize + nCount, -1); // grow it to new size
if( SUCCEEDED( hr ) )
{
// shift old data up to fill gap
memmove(&m_pData[nIndex+nCount], &m_pData[nIndex],
(nOldSize-nIndex) * sizeof(TYPE));
// re-init slots we copied from
hr = SPConstructElements(&m_pData[nIndex], nCount);
}
}
// insert new value in the gap
if( SUCCEEDED( hr ) )
{
SPDBG_ASSERT( nIndex + nCount <= m_nSize );
while (nCount--)
m_pData[nIndex++] = newElement;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -