summaryrefslogblamecommitdiffstats
path: root/private/ole32/dcomss/olescm/array_fv.cxx
blob: f353069d25e1c39afc2c522185925eff48394496 (plain) (tree)















































































































































































































































































































                                                                                                  
/////////////////////////////////////////////////////////////////////////////
//
// Implementation of Array of values
//
/////////////////////////////////////////////////////////////////////////////
// NOTE: we allocate an array of 'm_nMaxSize' elements, but only
//  the current size 'm_nSize' contains properly initialized elements
#include <headers.cxx>
#pragma hdrstop

#pragma SEG(array_fv)
ASSERTDATA

#include "scm.hxx"
#include "scm_afv.h"

#include <limits.h>
#define SIZE_T_MAX  UINT_MAX            /* max size for a size_t */


/////////////////////////////////////////////////////////////////////////////

#pragma SEG(CScmArrayFValue_ctor)
CScmArrayFValue::CScmArrayFValue(UINT cbValue)
{
	m_pData = NULL;
	m_cbValue = cbValue;
	m_nSize = m_nMaxSize = m_nGrowBy = 0;
}

#pragma SEG(CScmArrayFValue_dtor)
CScmArrayFValue::~CScmArrayFValue()
{
	ASSERT_VALID(this);

	ScmMemFree(m_pData);
}

// set new size; return FALSE if OOM

#pragma SEG(CScmArrayFValue_SetSize)
BOOL CScmArrayFValue::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
		ScmMemFree(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 *) ScmMemAlloc(nNewSize * m_cbValue);

		if (m_pData == NULL)
			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 *) ScmMemAlloc(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)
		ScmMemFree(m_pData);
		m_pData = pNewData;
		m_nSize = nNewSize;
		m_nMaxSize = nNewMax;
	}
	ASSERT_VALID(this);

	return TRUE;
}

#pragma SEG(CScmArrayFValue_FreeExtra)
void CScmArrayFValue::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 *) ScmMemAlloc(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)
		ScmMemFree(m_pData);
		m_pData = pNewData;
		m_nMaxSize = m_nSize;
	}
	ASSERT_VALID(this);
}

/////////////////////////////////////////////////////////////////////////////

#pragma SEG(CScmArrayFValue__GetAt)
LPVOID CScmArrayFValue::_GetAt(int nIndex) const
{
	ASSERT_VALID(this);
	Assert(nIndex >= 0 && nIndex < m_nSize);
	return &m_pData[nIndex * m_cbValue];
}

#pragma SEG(CScmArrayFValue_SetAt)
void CScmArrayFValue::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(CScmArrayFValue_SetAtGrow)
BOOL CScmArrayFValue::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(CScmArrayFValue_InsertAt)
BOOL CScmArrayFValue::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(CScmArrayFValue_RemoveAt)
void CScmArrayFValue::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(CScmArrayFValue_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 CScmArrayFValue::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* pElement;
	int nIndex;
	for (pElement = m_pData, nIndex = 0; nIndex < m_nSize; pElement += m_cbValue, nIndex++)
	{
		if (memcmp(pElement + offset, pData, cbData) == 0)
			return nIndex;
	}

	return -1;
}


/////////////////////////////////////////////////////////////////////////////


#pragma SEG(CScmArrayFValue_AssertValid)
void CScmArrayFValue::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
}