|
|
/*++
Copyright (c) Microsoft Corporation
Module Name:
fusionarray.h
Abstract:
Author:
Revision History:
--*/ #if !defined(FUSION_FUSIONARRAY_H_INCLUDED_)
#define FUSION_FUSIONARRAY_H_INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//
// fusionarray.h
//
// Fusion C++ array class. Functionally similar to ever other array
// class out there, but since we do not throw exceptions, instead this
// implementation does not define all the funky operators and
// instead defines member functions to access elements of the array
// which may return HRESULTs.
//
#if !defined(FUSION_UNUSED)
#define FUSION_UNUSED(x) (x)
#endif
#include <arrayhelp.h>
#include "CFusionArrayTypedefs.h"
#ifndef FUSION_ARRAY_DEFINED
#define FUSION_ARRAY_DEFINED
template <typename TStored, typename TPassed = TStored, bool fExponentialGrowth = false, int nDefaultSize = 0, int nGrowthParam = 1> #else
template <typename TStored, typename TPassed, bool fExponentialGrowth, int nDefaultSize, int nGrowthParam> #endif
class CFusionArray : public CFusionArrayTypedefs<TStored> { public: ConstIterator Begin() const { return m_prgtElements; }
ConstIterator End() const { return m_prgtElements + this->GetSize(); }
Iterator Begin() { return m_prgtElements; }
Iterator End() { return m_prgtElements + this->GetSize(); }
template <typename Integer> Reference operator[](Integer index) { return *(Begin() + index); }
template <typename Integer> ConstReference operator[](Integer index) const { return *(Begin() + index); }
CFusionArray() : m_prgtElements(NULL), m_cElements(0), m_iHighWaterMark(0) { C_ASSERT(nGrowthParam >= 1); }
~CFusionArray() { ::FusionFreeArray(m_cElements, m_prgtElements); m_prgtElements = NULL; m_cElements = 0; m_iHighWaterMark = 0; }
BOOL Win32Initialize(SIZE_T nSize = nDefaultSize) { FN_PROLOG_WIN32
INTERNAL_ERROR_CHECK(m_cElements == 0);
if (nSize != 0) { IFW32FALSE_EXIT(::FusionWin32ResizeArray(m_prgtElements, m_cElements, nSize)); m_cElements = nSize; }
FN_EPILOG }
BOOL Win32Access(SIZE_T iElement, TStored *&rptOut, bool fExtendIfNecessary = false) { FN_PROLOG_WIN32 rptOut = NULL;
PARAMETER_CHECK(fExtendIfNecessary || (iElement < m_cElements));
if (iElement >= m_cElements) IFW32FALSE_EXIT(this->Win32InternalExpand(iElement));
rptOut = &m_prgtElements[iElement];
if (iElement >= m_iHighWaterMark) m_iHighWaterMark = iElement + 1; FN_EPILOG }
// HRESULT GetSize(SIZE_T &rcElementsOut) const { rcElementsOut = m_cElements; return NOERROR; }
SIZE_T GetSize() const { return m_cElements; }
DWORD GetSizeAsDWORD() const { if (m_cElements > MAXDWORD) return MAXDWORD; return static_cast<DWORD>(m_cElements); } ULONG GetSizeAsULONG() const { if (m_cElements > ULONG_MAX) return ULONG_MAX; return static_cast<ULONG>(m_cElements); }
//
// Enumeration used to control the behavior of CFusionArray::SetSize().
// if eSetSizeModeExact is passed, the internal array is set to exactly
// the cElements passed in; if eSetSizeModeApplyRounding is passed (the
// default), we apply the normal expansion/shrinking algorithm for the
// array.
//
enum SetSizeMode { eSetSizeModeExact = 0, eSetSizeModeApplyRounding = 1, };
//
// Member function to manually set the size of the internal array stored
// by the CFusionArray. Default behavior is to find an appropriate rounded
// size (based on the exponential vs. linear growth characteristic of the
// array) and resize to that. Alternately, the caller may supply an
// exact size and the internal size is set to that. Note that explicitly
// setting the array size may have interesting side-effects on future
// growth of the array; for example if an array is set to grow exponentially
// at a factor of 2^1 (nGrowthFactor == 1; doubling on each growth pass),
// its size will normally be a power of two. However, explicitly setting the
// size to, for example, 10 and then trying to access element 11 will cause
// the exponential growth factor to grow the array to 20 elements, rather than
// a power of two.
//
BOOL Win32SetSize(SIZE_T cElements, SetSizeMode ssm = eSetSizeModeApplyRounding) { FN_PROLOG_WIN32
if (ssm == eSetSizeModeExact) { IFW32FALSE_EXIT(::FusionWin32ResizeArray(m_prgtElements, m_cElements, cElements));
if (cElements < m_iHighWaterMark) m_iHighWaterMark = cElements;
m_cElements = cElements; } else { if (cElements > m_cElements) { IFW32FALSE_EXIT(this->Win32InternalExpand(cElements - 1)); } else { // For now, since it's inexact, we'll punt non-exact shrinking.
} }
FN_EPILOG }
const TStored *GetArrayPtr() const { return m_prgtElements; } TStored *GetArrayPtr() { return m_prgtElements; }
//
// Member function to reset the array to its size and storage associated with
// its initial construction.
//
enum ResetMode { eResetModeZeroSize = 0, eResetModeDefaultSize = 1, };
BOOL Win32Reset(ResetMode rm = eResetModeDefaultSize) { FN_PROLOG_WIN32
if (rm == eResetModeDefaultSize) { if (m_cElements != nDefaultSize) { IFW32FALSE_EXIT(::FusionWin32ResizeArray(m_prgtElements, m_cElements, nDefaultSize)); m_cElements = nDefaultSize; } if (m_iHighWaterMark > nDefaultSize) m_iHighWaterMark = nDefaultSize; } else if (rm == eResetModeZeroSize) { ::FusionFreeArray(m_cElements, m_prgtElements); m_prgtElements = NULL; m_cElements = m_iHighWaterMark = 0; } FN_EPILOG }
enum AppendMode { eAppendModeExtendArray = 0, eAppendModeNoExtendArray = 1, };
BOOL Win32Append(const TPassed& tNew, AppendMode am = eAppendModeExtendArray) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
INTERNAL_ERROR_CHECK(m_iHighWaterMark <= m_cElements);
PARAMETER_CHECK((am != eAppendModeNoExtendArray) || (m_iHighWaterMark < m_cElements));
if (m_iHighWaterMark >= m_cElements) { SIZE_T cElementsOld = m_cElements; IFW32FALSE_EXIT(this->Win32InternalExpand(m_cElements)); m_iHighWaterMark = cElementsOld; }
// Clients of this class should provide explicit overrides for FusionCopyContents()
// for their types as appropriate.
IFW32FALSE_EXIT(::FusionWin32CopyContents(m_prgtElements[m_iHighWaterMark++], tNew));
fSuccess = TRUE; Exit: return fSuccess; }
BOOL Win32Remove(SIZE_T i) { FN_PROLOG_WIN32
SIZE_T j;
INTERNAL_ERROR_CHECK(m_iHighWaterMark <= m_cElements);
PARAMETER_CHECK(i < m_cElements);
for (j = (i + 1); j < m_cElements; j++) IFW32FALSE_EXIT(::FusionWin32CopyContents(m_prgtElements[j-1], m_prgtElements[j]));
m_cElements--; m_iHighWaterMark--;
FN_EPILOG }
// 03/14/2001 - Added constness
BOOL Win32Assign(SIZE_T celt, const TPassed *prgtelt) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); SIZE_T i;
// So that we can fail gracefully, we need to copy our state off, attempt
// the population of the array and then revert if necessary.
TStored *prgtElementsSaved = m_prgtElements; SIZE_T cElementsSaved = m_cElements; SIZE_T iHighWaterMarkSaved = m_iHighWaterMark;
PARAMETER_CHECK((celt == 0) || (prgtelt != NULL));
m_prgtElements = NULL; m_cElements = 0; m_iHighWaterMark = 0;
IFW32FALSE_EXIT(this->Win32Initialize(celt));
for (i=0; i<celt; i++) { IFW32FALSE_EXIT(::FusionWin32CopyContents(m_prgtElements[i], prgtelt[i])); }
m_iHighWaterMark = celt;
// We can drop the old contents...
::FusionFreeArray(cElementsSaved, prgtElementsSaved); cElementsSaved = 0; prgtElementsSaved = NULL;
fSuccess = TRUE;
Exit: if (!fSuccess) { // Revert to previous state...
::FusionFreeArray(m_cElements, m_prgtElements); m_prgtElements = prgtElementsSaved; m_cElements = cElementsSaved; m_iHighWaterMark = iHighWaterMarkSaved; }
return fSuccess; }
// Xiaoyu 01/24/00 : copy this to prgDest
//
// jonwis 20-Sept-2000 : Update to be a little cleaner and 'const'
//
BOOL Win32Clone(CFusionArray<TStored, TPassed> &prgDest) const { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess);
SIZE_T i;
//
// Cloning an empty array shouldn't break things.
//
if (m_prgtElements == NULL) { IFW32FALSE_EXIT(prgDest.Win32Reset(eResetModeZeroSize)); } else {
//
// Resize the destiny array to what it should be
//
if (prgDest.m_cElements != m_cElements) IFW32FALSE_EXIT(::FusionWin32ResizeArray(prgDest.m_prgtElements, prgDest.m_cElements, m_cElements));
//
// Copy the elements from point A to point B
//
for (i = 0; i < m_cElements; i++) { IFW32FALSE_EXIT(::FusionWin32CopyContents(prgDest.m_prgtElements[i], m_prgtElements[i])); }
prgDest.m_cElements = m_cElements; prgDest.m_iHighWaterMark = m_iHighWaterMark; } fSuccess = TRUE;
Exit: if (!fSuccess) { prgDest.Win32Reset(eResetModeZeroSize); }
return fSuccess; }
protected:
BOOL Win32InternalExpand(SIZE_T iElement) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); SIZE_T nNewElements = 0;
if (fExponentialGrowth) { if (m_cElements == 0) { if (nDefaultSize == 0) nNewElements = (1 << nGrowthParam); else nNewElements = nDefaultSize; } else { nNewElements = m_cElements * (1 << nGrowthParam); }
while ((nNewElements != 0) && (nNewElements <= iElement)) nNewElements = nNewElements << nGrowthParam;
// Ok, it's possible that nGrowthParam was something crazy like 10
// (meaning to grow the array by a factor of 2^10 each time), so we
// never really found a size that was appropriate. We'll be slightly
// less crazy and find the power-of-two that's big enough. We still
// have a possibility here that the user is asking for an index between
// 2^31 and ((2^32)-1), which of course will fail because we can't
// allocate that much storage.
if (nNewElements == 0) { nNewElements = 1;
while ((nNewElements != 0) && (nNewElements <= iElement)) nNewElements = nNewElements << 1; } } else { // In the linear growth case, we can use simple division to do all the
// work done above for exponential growth.
nNewElements = iElement + nGrowthParam - 1;
if (nGrowthParam > 1) nNewElements = nNewElements - (nNewElements % nGrowthParam);
// We'll handle overflow in the generic checking below...
}
// fallback; we'll try to make it just big enough. It's true we lose the
// growth pattern etc. that the caller requested, but it's pretty clear that
// the caller messed up by either specifying a wacky nGrowthParam or there's
// an outlandishly large iElement coming in.
if (nNewElements <= iElement) nNewElements = iElement + 1;
IFW32FALSE_EXIT(::FusionWin32ResizeArray(m_prgtElements, m_cElements, nNewElements));
m_cElements = nNewElements;
fSuccess = TRUE;
Exit: return fSuccess; }
TStored *m_prgtElements; SIZE_T m_cElements; SIZE_T m_iHighWaterMark; };
#endif // !defined(FUSION_FUSIONARRAY_H_INCLUDED_)
|