mirror of https://github.com/lianthony/NT4.0
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.
342 lines
8.4 KiB
342 lines
8.4 KiB
//+---------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1993 - 1994.
|
|
//
|
|
// File: d:\nt\private\cairole\com\coll\array_fv.cxx
|
|
//
|
|
// Contents: Implementation of Array of values
|
|
//
|
|
// Classes: CArrayFValue
|
|
//
|
|
// Functions: CArrayFValue::CArrayFValue
|
|
// CArrayFValue::~CArrayFValue
|
|
// CArrayFValue::SetSize
|
|
// CArrayFValue::FreeExtra
|
|
// CArrayFValue::_GetAt
|
|
// CArrayFValue::SetAt
|
|
// CArrayFValue::SetAtGrow
|
|
// CArrayFValue::InsertAt
|
|
// CArrayFValue::RemoveAt
|
|
// CArrayFValue::IndexOf
|
|
// CArrayFValue::AssertValid
|
|
//
|
|
// History: 26-Jul-94 BruceMa Created this file header
|
|
// 26-Jul-94 BruceMa Memory sift fix
|
|
//
|
|
//----------------------------------------------------------------------
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// NOTE: we allocate an array of 'm_nMaxSize' elements, but only
|
|
// the current size 'm_nSize' contains properly initialized elements
|
|
|
|
#include <ole2int.h>
|
|
//#include <compobj.seg>
|
|
#pragma SEG(array_fv)
|
|
ASSERTDATA
|
|
|
|
#include "array_fv.h"
|
|
|
|
#include <limits.h>
|
|
#define SIZE_T_MAX UINT_MAX /* max size for a size_t */
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma SEG(CArrayFValue_ctor)
|
|
CArrayFValue::CArrayFValue(UINT cbValue)
|
|
{
|
|
m_pData = NULL;
|
|
m_cbValue = cbValue;
|
|
m_nSize = m_nMaxSize = m_nGrowBy = 0;
|
|
}
|
|
|
|
#pragma SEG(CArrayFValue_dtor)
|
|
CArrayFValue::~CArrayFValue()
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
PrivMemFree(m_pData);
|
|
}
|
|
|
|
// set new size; return FALSE if OOM
|
|
|
|
#pragma SEG(CArrayFValue_SetSize)
|
|
BOOL CArrayFValue::SetSize(int nNewSize, int nGrowBy /* = -1 */)
|
|
{
|
|
ASSERT_VALID(this);
|
|
Assert(nNewSize >= 0);
|
|
|
|
if (nGrowBy != -1)
|
|
m_nGrowBy = nGrowBy; // set new size
|
|
|
|
if (nNewSize == 0)
|
|
{
|
|
// shrink to nothing
|
|
PrivMemFree(m_pData);
|
|
m_pData = NULL;
|
|
m_nSize = m_nMaxSize = 0;
|
|
}
|
|
else if (m_pData == NULL)
|
|
{
|
|
// create one with exact size
|
|
Assert((long)nNewSize * m_cbValue <= SIZE_T_MAX); // no overflow
|
|
|
|
m_pData = (BYTE FAR*)PrivMemAlloc(nNewSize * m_cbValue);
|
|
if (m_pData == NULL)
|
|
{
|
|
m_nSize = m_nMaxSize = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
memset(m_pData, 0, nNewSize * m_cbValue); // zero fill
|
|
m_nSize = m_nMaxSize = nNewSize;
|
|
}
|
|
else if (nNewSize <= m_nMaxSize)
|
|
{
|
|
// it fits
|
|
if (nNewSize > m_nSize)
|
|
{
|
|
// initialize the new elements
|
|
memset(&m_pData[m_nSize * m_cbValue], 0, (nNewSize-m_nSize) * m_cbValue);
|
|
}
|
|
m_nSize = nNewSize;
|
|
}
|
|
else
|
|
{
|
|
// Otherwise grow array
|
|
int nNewMax;
|
|
if (nNewSize < m_nMaxSize + m_nGrowBy)
|
|
nNewMax = m_nMaxSize + m_nGrowBy; // granularity
|
|
else
|
|
nNewMax = nNewSize; // no slush
|
|
|
|
Assert((long)nNewMax * m_cbValue <= SIZE_T_MAX); // no overflow
|
|
|
|
BYTE FAR* pNewData = (BYTE FAR*)PrivMemAlloc(nNewMax * m_cbValue);
|
|
if (pNewData == NULL)
|
|
return FALSE;
|
|
|
|
// copy new data from old
|
|
memcpy(pNewData, m_pData, m_nSize * m_cbValue);
|
|
|
|
// construct remaining elements
|
|
Assert(nNewSize > m_nSize);
|
|
memset(&pNewData[m_nSize * m_cbValue], 0, (nNewSize-m_nSize) * m_cbValue);
|
|
|
|
// get rid of old stuff (note: no destructors called)
|
|
PrivMemFree(m_pData);
|
|
m_pData = pNewData;
|
|
m_nSize = nNewSize;
|
|
m_nMaxSize = nNewMax;
|
|
}
|
|
ASSERT_VALID(this);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#pragma SEG(CArrayFValue_FreeExtra)
|
|
void CArrayFValue::FreeExtra()
|
|
{
|
|
ASSERT_VALID(this);
|
|
|
|
if (m_nSize != m_nMaxSize)
|
|
{
|
|
// shrink to desired size
|
|
Assert((long)m_nSize * m_cbValue <= SIZE_T_MAX); // no overflow
|
|
|
|
BYTE FAR* pNewData = (BYTE FAR*)PrivMemAlloc(m_nSize * m_cbValue);
|
|
if (pNewData == NULL)
|
|
return; // can't shrink; don't to anything
|
|
|
|
// copy new data from old
|
|
memcpy(pNewData, m_pData, m_nSize * m_cbValue);
|
|
|
|
// get rid of old stuff (note: no destructors called)
|
|
PrivMemFree(m_pData);
|
|
m_pData = pNewData;
|
|
m_nMaxSize = m_nSize;
|
|
}
|
|
ASSERT_VALID(this);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma SEG(CArrayFValue__GetAt)
|
|
LPVOID CArrayFValue::_GetAt(int nIndex) const
|
|
{
|
|
ASSERT_VALID(this);
|
|
Assert(nIndex >= 0 && nIndex < m_nSize);
|
|
return &m_pData[nIndex * m_cbValue];
|
|
}
|
|
|
|
#pragma SEG(CArrayFValue_SetAt)
|
|
void CArrayFValue::SetAt(int nIndex, LPVOID pValue)
|
|
{
|
|
ASSERT_VALID(this);
|
|
Assert(nIndex >= 0 && nIndex < m_nSize);
|
|
|
|
memcpy(&m_pData[nIndex * m_cbValue], pValue, m_cbValue);
|
|
}
|
|
|
|
#pragma SEG(CArrayFValue_SetAtGrow)
|
|
BOOL CArrayFValue::SetAtGrow(int nIndex, LPVOID pValue)
|
|
{
|
|
ASSERT_VALID(this);
|
|
Assert(nIndex >= 0);
|
|
if (nIndex >= m_nSize && !SetSize(nIndex+1))
|
|
return FALSE;
|
|
|
|
SetAt(nIndex, pValue);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#pragma SEG(CArrayFValue_InsertAt)
|
|
BOOL CArrayFValue::InsertAt(int nIndex, LPVOID pValue, int nCount /*=1*/)
|
|
{
|
|
ASSERT_VALID(this);
|
|
Assert(nIndex >= 0); // will expand to meet need
|
|
Assert(nCount > 0); // zero or negative size not allowed
|
|
|
|
if (nIndex >= m_nSize)
|
|
{
|
|
// adding after the end of the array
|
|
if (!SetSize(nIndex + nCount)) // grow so nIndex is valid
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
// inserting in the middle of the array
|
|
int nOldSize = m_nSize;
|
|
if (!SetSize(m_nSize + nCount)) // grow it to new size
|
|
return FALSE;
|
|
|
|
// shift old data up to fill gap
|
|
memmove(&m_pData[(nIndex+nCount) * m_cbValue],
|
|
&m_pData[nIndex * m_cbValue],
|
|
(nOldSize-nIndex) * m_cbValue);
|
|
|
|
// re-init slots we copied from
|
|
memset(&m_pData[nIndex * m_cbValue], 0, nCount * m_cbValue);
|
|
}
|
|
|
|
// insert new value in the gap
|
|
Assert(nIndex + nCount <= m_nSize);
|
|
while (nCount--)
|
|
memcpy(&m_pData[nIndex++ * m_cbValue], pValue, m_cbValue);
|
|
|
|
ASSERT_VALID(this);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#pragma SEG(CArrayFValue_RemoveAt)
|
|
void CArrayFValue::RemoveAt(int nIndex, int nCount /* = 1 */)
|
|
{
|
|
ASSERT_VALID(this);
|
|
Assert(nIndex >= 0);
|
|
Assert(nIndex < m_nSize);
|
|
Assert(nCount >= 0);
|
|
Assert(nIndex + nCount <= m_nSize);
|
|
|
|
// just remove a range
|
|
int nMoveCount = m_nSize - (nIndex + nCount);
|
|
if (nMoveCount)
|
|
memcpy(&m_pData[nIndex * m_cbValue],
|
|
&m_pData[(nIndex + nCount) * m_cbValue],
|
|
nMoveCount * m_cbValue);
|
|
m_nSize -= nCount;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#pragma SEG(CArrayFValue_IndexOf)
|
|
// find element given part of one; offset is offset into value; returns
|
|
// -1 if element not found; use IndexOf(NULL, cb, offset) to find zeros;
|
|
// will be optimized for appropriate value size and param combinations
|
|
int CArrayFValue::IndexOf(LPVOID pData, UINT cbData, UINT offset)
|
|
{
|
|
Assert(offset <= m_cbValue);
|
|
Assert(cbData <= m_cbValue);
|
|
Assert((long)offset + cbData <= m_cbValue);
|
|
Assert(!IsBadReadPtr(pData, cbData));
|
|
|
|
#ifdef LATER
|
|
if (cbData == sizeof(WORD) && m_cbValue == sizeof(WORD))
|
|
{
|
|
int iwRet;
|
|
_asm
|
|
{
|
|
push di
|
|
les di,pData ;* get value
|
|
mov ax,es:[di] ;* from *(WORD FAR*)pData
|
|
les di,this
|
|
mov cx,[di].m_nSize ;* get size (in WORDs) of array
|
|
les di,[di].m_pData ;* get ptr to WORD array
|
|
repne scasw ;* look for *(WORD FAR*)pData
|
|
jeq retcx ;* brif found
|
|
xor cx,cx ;* return -1
|
|
retcx:
|
|
dec cx
|
|
mov iwRet,cx
|
|
pop di
|
|
}
|
|
|
|
return iwRet;
|
|
}
|
|
#endif
|
|
BYTE FAR* pCompare = m_pData + offset; // points to the value to compare
|
|
int nIndex = 0;
|
|
|
|
if (cbData == sizeof(WORD)) {
|
|
for (; nIndex < m_nSize; pCompare += m_cbValue, nIndex++)
|
|
{
|
|
if (*(WORD FAR*)pCompare == *(WORD FAR*)pData)
|
|
return nIndex;
|
|
}
|
|
} else if (cbData == sizeof(LONG)) {
|
|
for (; nIndex < m_nSize; pCompare += m_cbValue, nIndex++)
|
|
{
|
|
if (*(LONG FAR*)pCompare == *(LONG FAR*)pData)
|
|
return nIndex;
|
|
}
|
|
} else {
|
|
for (; nIndex < m_nSize; pCompare += m_cbValue, nIndex++)
|
|
{
|
|
if (memcmp(pCompare, pData, cbData) == 0)
|
|
return nIndex;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
#pragma SEG(CArrayFValue_AssertValid)
|
|
void CArrayFValue::AssertValid() const
|
|
{
|
|
#ifdef _DEBUG
|
|
if (m_pData == NULL)
|
|
{
|
|
Assert(m_nSize == 0);
|
|
Assert(m_nMaxSize == 0);
|
|
}
|
|
else
|
|
{
|
|
Assert(m_nSize <= m_nMaxSize);
|
|
Assert((long)m_nMaxSize * m_cbValue <= SIZE_T_MAX); // no overflow
|
|
Assert(!IsBadReadPtr(m_pData, m_nMaxSize * m_cbValue));
|
|
}
|
|
|
|
// some collections live as global variables in the libraries, but
|
|
// have their existance in some context. Also, we can't check shared
|
|
// collections since we might be checking the etask collection
|
|
// which would cause an infinite recursion.
|
|
#endif //_DEBUG
|
|
}
|