/******************************************************************** Copyright (c) 2000 Microsoft Corporation Module Name: PFArray.cpp Abstract: dynamic array implementation. This dynamic array is NOT thread safe. Revision History: DerekM modified 03/14/00 ********************************************************************/ #include "stdafx.h" #include "pfarray.h" ///////////////////////////////////////////////////////////////////////////// // tracing #ifdef THIS_FILE #undef THIS_FILE #endif static char __szTraceSourceFile[] = __FILE__; #define THIS_FILE __szTraceSourceFile ///////////////////////////////////////////////////////////////////////////// // CPFArrayBase initialization & deinitialization // ************************************************************************** CPFArrayBase::CPFArrayBase(void) { m_pfnAlloc = NULL; m_pfnDelete = NULL; m_rgpv = NULL; m_cSlots = 0; m_iHighest = (DWORD)-1; } // ************************************************************************** CPFArrayBase::~CPFArrayBase(void) { this->CompressArray(0, (DWORD)-1); if (m_rgpv != NULL) MyFree(m_rgpv, g_hPFPrivateHeap); } ///////////////////////////////////////////////////////////////////////////// // CAUOPropDB internal methods // *************************************************************************** inline HRESULT CPFArrayBase::Grow(DWORD iMinLast) { USE_TRACING("CPFArrayBase::SetItem"); HRESULT hr = NOERROR; if (iMinLast >= m_cSlots || m_rgpv == NULL) { LPVOID *rgpv = NULL; DWORD cSlots; cSlots = MyMax(iMinLast + 1, 8); cSlots = MyMax(m_cSlots * 2, cSlots); rgpv = (LPVOID *)MyAlloc(cSlots * sizeof(LPVOID), g_hPFPrivateHeap); VALIDATEEXPR(hr, (rgpv == NULL), E_OUTOFMEMORY); if (FAILED(hr)) goto done; if (m_rgpv != NULL) { CopyMemory(rgpv, m_rgpv, m_cSlots * sizeof(LPVOID)); MyFree(m_rgpv); } m_rgpv = rgpv; m_cSlots = cSlots; } done: return hr; } // *************************************************************************** inline HRESULT CPFArrayBase::CompressArray(DWORD iStart, DWORD iEnd) { USE_TRACING("CPFArrayBase::CompressArray"); _ASSERT(iStart < iEnd); // don't need to do anything cuz we're already empty if (m_iHighest == (DWORD)-1) return NOERROR; if (iStart <= m_iHighest) { DWORD i; // note that this will also catch passing -1 for iEnd cuz (DWORD)-1 // is greater than any other DWORD value... Of course, this // assumes that we don't have 2^32 - 1 elements. While it is // theoretically possible to have an array that big on ia64, this // class can't be used for it. if (iEnd > m_iHighest + 1) iEnd = m_iHighest + 1; for(i = iStart; i < iEnd; i++) { if (m_rgpv[i] != NULL) this->DeleteItem(m_rgpv[i]); } // no point in doing a move if we're not going to be moving anything if (iEnd <= m_iHighest) { MoveMemory(&m_rgpv[iStart], &m_rgpv[iEnd], (m_iHighest - iEnd + 1) * sizeof(LPVOID)); } } m_iHighest -= (iEnd - iStart); return NOERROR; } // *************************************************************************** HRESULT CPFArrayBase::internalCopyFrom(CPFArrayBase *prg) { USE_TRACING("CPFArrayBase::CopyFrom"); HRESULT hr = NOERROR; DWORD i; // if it's at -1, then we've deleted everything already... if (prg->m_iHighest == (DWORD)-1) goto done; TESTHR(hr, this->Grow(prg->m_iHighest + 1)); if (FAILED(hr)) goto done; for(i = 0; i < prg->m_iHighest + 1; i++) { m_rgpv[i] = prg->AllocItemCopy(prg->m_rgpv[i]); VALIDATEEXPR(hr, (m_rgpv[i] == NULL), E_OUTOFMEMORY); if (FAILED(hr)) { this->RemoveAll(); goto done; } } done: return hr; } ///////////////////////////////////////////////////////////////////////////// // CPFArrayBase exposed methods / properties // *************************************************************************** HRESULT CPFArrayBase::Init(DWORD cSlots) { USE_TRACING("CPFArrayBase::Init"); HRESULT hr = NOERROR; VALIDATEEXPR(hr, (m_rgpv != NULL), E_FAIL); if (FAILED(hr)) goto done; TESTHR(hr, this->Grow(cSlots - 1)); if (FAILED(hr)) goto done; done: return hr; } // *************************************************************************** LPVOID &CPFArrayBase::operator [](DWORD iItem) { USE_TRACING("CPFArrayBase::operator []"); if (iItem >= m_cSlots || m_rgpv == NULL) { HRESULT hr; TESTHR(hr, this->Grow(iItem)); _ASSERT(SUCCEEDED(hr)); } // since we have to return a reference, we can't do much about Grow failing // which means of course that we could fault... return m_rgpv[iItem]; } // *************************************************************************** HRESULT CPFArrayBase::get_Item(DWORD iItem, LPVOID *ppv) { USE_TRACING("CPFArrayBase::get_Item"); HRESULT hr = NOERROR; VALIDATEPARM(hr, (ppv == NULL)) if (FAILED(hr)) goto done; if (iItem >= m_cSlots || m_rgpv == NULL) { TESTHR(hr, this->Grow(iItem)); if (FAILED(hr)) goto done; } if (ppv != NULL) *ppv = m_rgpv[iItem]; done: return hr; } // *************************************************************************** HRESULT CPFArrayBase::put_Item(DWORD iItem, LPVOID pv, LPVOID *ppvOld) { USE_TRACING("CPFArrayBase::put_Item"); HRESULT hr = NOERROR; if (iItem >= m_cSlots || m_rgpv == NULL) { TESTHR(hr, this->Grow(m_iHighest + 1)); if (FAILED(hr)) goto done; } if (ppvOld != NULL) *ppvOld = m_rgpv[iItem]; else if (m_rgpv[iItem] != NULL) this->DeleteItem(m_rgpv[iItem]); m_rgpv[iItem] = pv; if (iItem > m_iHighest) m_iHighest = iItem; done: return hr; } // *************************************************************************** HRESULT CPFArrayBase::Append(LPVOID pv) { USE_TRACING("CPFArrayBase::Append"); HRESULT hr = NOERROR; if (pv == NULL) pv = NULL; if (m_iHighest + 1 >= m_cSlots || m_rgpv == NULL) { TESTHR(hr, this->Grow(m_iHighest + 1)); if (FAILED(hr)) goto done; } m_iHighest++; m_rgpv[m_iHighest] = pv; done: return hr; } // *************************************************************************** HRESULT CPFArrayBase::Remove(DWORD iItem, LPVOID *ppvOld) { USE_TRACING("CPFArrayBase::Remove"); HRESULT hr = NOERROR; if (iItem > m_iHighest) goto done; if (ppvOld != NULL) *ppvOld = m_rgpv[iItem]; TESTHR(hr, this->CompressArray(iItem, iItem + 1)); if (FAILED(hr)) return hr; done: return hr; } // *************************************************************************** HRESULT CPFArrayBase::RemoveAll(void) { USE_TRACING("CPFArrayBase::RemoveAll"); HRESULT hr = NOERROR; // if it's at -1, then we've deleted everything already... if (m_iHighest == (DWORD)-1) goto done; TESTHR(hr, this->CompressArray(0, (DWORD)-1)); if (FAILED(hr)) return hr; done: return hr; }