558 lines
20 KiB
C++
558 lines
20 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Forms
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1996.
|
|
//
|
|
// File: formsary.hxx
|
|
//
|
|
// Contents: CImplAry* classes
|
|
//
|
|
// Stolen from Trident
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// This is the implementation of the generic resizeable array classes. There
|
|
// are four array classes:
|
|
//
|
|
// CPtrAry<ELEM> --
|
|
//
|
|
// Dynamic array class which is optimized for sizeof(ELEM) equal
|
|
// to 4. The array is initially empty with no space or memory allocated
|
|
// for data.
|
|
//
|
|
// CDataAry<ELEM> --
|
|
//
|
|
// Same as CPtrAry but where sizeof(ELEM) is != 4 and less than 128.
|
|
//
|
|
// CStackPtrAry<ELEM, N> --
|
|
//
|
|
// Dynamic array class optimized for sizeof(ELEM) equal to 4.
|
|
// Space for N elements is allocated as member data of the class. If
|
|
// this class is created on the stack, then space for N elements will
|
|
// be created on the stack. The class can grow beyond N elements, at
|
|
// which point memory will be allocated for the array data.
|
|
//
|
|
// CStackDataAry<ELEM, N> --
|
|
//
|
|
// Same as CStackPtrAry, but where sizeof(ELEM) is != 4 and less than 128.
|
|
//
|
|
//
|
|
// All four classes have virtually the same methods, and are used the same.
|
|
// The only difference is that the DataAry classes have AppendIndirect and
|
|
// InsertIndirect, while the PtrAry classes use Append and Insert. The reason
|
|
// for the difference is that the Indirect methods take a pointer to the data,
|
|
// while the non-indirect methods take the actual data as an argument.
|
|
//
|
|
// The Stack arrays (CStackPtrAry and CStackDataAry) are used to pre-allocate
|
|
// space for elements in the array. This is useful if you create the array on
|
|
// the stack and you know that most of the time the array will be less than
|
|
// a certain number of elements. Creating one of these arrays on the stack
|
|
// allocates the array on the stack as well, preventing a separate memory
|
|
// allocation. Only if the array grows beyond the initial size will any
|
|
// additional memory be allocated.
|
|
//
|
|
// The fastest and most efficient way of looping through all elements in
|
|
// the array is as follows:
|
|
//
|
|
// ELEM * pElem;
|
|
// int i;
|
|
//
|
|
// for (i = aryElems.Size(), pElem = aryElems;
|
|
// i > 0;
|
|
// i--, pElem++)
|
|
// {
|
|
// (*pElem)->DoSomething();
|
|
// }
|
|
//
|
|
// This loop syntax has been shown to be the fastest and produce the smallest
|
|
// code. Here's an example using a real data type:
|
|
//
|
|
// CStackPtrAry<CSite*, 16> arySites;
|
|
// CSite **ppSite;
|
|
// int i;
|
|
//
|
|
// // Populate the array.
|
|
// ...
|
|
//
|
|
// // Now loop through every element in the array.
|
|
// for (i = arySites.Size(), ppSite = arySites;
|
|
// i > 0;
|
|
// i--, ppSite++)
|
|
// {
|
|
// (*ppSite)->DoSomething();
|
|
// }
|
|
//
|
|
// METHOD DESCRIPTIONS:
|
|
//
|
|
// Commonly used methods:
|
|
//
|
|
// Size() Returns the number of elements currently stored
|
|
// in the array.
|
|
//
|
|
// operator [] Returns the given element in the array.
|
|
//
|
|
// Item(int i) Returns the given element in the array.
|
|
//
|
|
// operator ELEM* Allows the array class to be cast to a pointer
|
|
// to ELEM. Returns a pointer to the first element
|
|
// in the array. (Same as a Base() method).
|
|
//
|
|
// Append(ELEM e) Adds a new pointer to the end of the array,
|
|
// growing the array if necessary. Only valid
|
|
// for arrays of pointers (CPtrAry, CStackPtrAry).
|
|
//
|
|
// AppendIndirect(ELEM *pe, ELEM** ppePlaced)
|
|
// As Append, for non-pointer arrays
|
|
// (CDataAry, CStackDataAry).
|
|
// pe [in] - Pointer to element to add to array. The
|
|
// data is copied into the array. Can be
|
|
// NULL, in which case the new element is
|
|
// initialized to all zeroes.
|
|
// ppePlaced [out] - Returns pointer to the new
|
|
// element. Can be NULL.
|
|
//
|
|
// Insert(int i, ELEM e)
|
|
// Inserts a new element (e) at the given index (i)
|
|
// in the array, growing the array if necessary. Any
|
|
// elements at or following the index are moved
|
|
// out of the way.
|
|
//
|
|
// InsertIndirect(int i, ELEM *pe)
|
|
// As Insert, for non-pointer arrays
|
|
// (CDataAry, CStackDataAry).
|
|
//
|
|
// Find(ELEM e) Returns the index at which a given element (e)
|
|
// is found (CPtrAry, CStackPtrAry).
|
|
//
|
|
// FindIndirect(ELEM *pe)
|
|
// As Find, for non-pointer arrays
|
|
// (CDataAry, CStackDataAry).
|
|
//
|
|
// DeleteAll() Empties the array and de-allocates associated
|
|
// memory.
|
|
//
|
|
// Delete(int i) Deletes an element of the array, moving any
|
|
// elements that follow it to fill
|
|
//
|
|
// DeleteMultiple(int start, int end)
|
|
// Deletes a range of elements from the array,
|
|
// moving to fill. [start] and [end] are the indices
|
|
// of the start and end elements (inclusive).
|
|
//
|
|
// DeleteByValue(ELEM e)
|
|
// Delete the element matching the given value.
|
|
//
|
|
// DeleteByValueIndirect(ELEM *pe)
|
|
// As DeleteByValue, for non-pointer arrays.
|
|
// (CDataAry, CStackDataAry).
|
|
//
|
|
//
|
|
// Less commonly used methods:
|
|
//
|
|
// EnsureSize(long c) If you know how many elements you are going to put
|
|
// in the array before you actually do it, you can use
|
|
// EnsureSize to allocate the memory all at once instead
|
|
// of relying on Append(Indirect) to grow the array. This
|
|
// can be much more efficient (by causing only a single
|
|
// memory allocation instead of many) than just using
|
|
// Append(Indirect). You pass in the number of elements
|
|
// that memory should be allocated for. Note that this
|
|
// does not affect the "Size" of the array, which is
|
|
// the number of elements currently stored in it.
|
|
//
|
|
// SetSize(int c) Sets the "Size" of the array, which is the number
|
|
// of elements currently stored in it. SetSize will not
|
|
// allocate memory if you're growing the array.
|
|
// EnsureSize must be called first to reserve space if
|
|
// the array is growing. Setting the size smaller does
|
|
// not de-allocate memory, it just chops off the
|
|
// elements at the end of the array.
|
|
//
|
|
// Grow(int c) Equivalent to calling EnsureSize(c) followed by
|
|
// SetSize(c).
|
|
//
|
|
// ReleaseAll() (CPtrAry and CStackPtrAry only) Calls Release()
|
|
// on each element in the array and empties the array.
|
|
//
|
|
// ReleaseAndDelete(int idx)
|
|
// (CPtrAry and CStackPtrAry only) Calls Release() on
|
|
// the given element and removes it from the array.
|
|
//
|
|
// (See the class definitions below for signatures of the following
|
|
// methods and src\core\cdutil\formsary.cxx for argument
|
|
// descriptions)
|
|
//
|
|
// CopyAppend Appends data from another array (of the same type)
|
|
// to the end.
|
|
//
|
|
// Copy Copies data from another array (of the same type)
|
|
// into this array, replacing any existing data.
|
|
//
|
|
// CopyAppendIndirect Appends data from a C-style array of element data
|
|
// to the end of this array.
|
|
//
|
|
// CopyIndirect Copies elements from a C-style array into this array
|
|
// replacing any existing data.
|
|
//
|
|
// EnumElements Create an enumerator which supports the given
|
|
// interface ID for the contents of the array
|
|
//
|
|
// EnumVARIANT Create an IEnumVARIANT enumerator.
|
|
//
|
|
// operator void * Allow the CImplAry class to be cast
|
|
// to a (void *). Avoid using if possible - use
|
|
// the type-safe operator ELEM * instead.
|
|
//
|
|
// ClearAndReset Obsolete. Do not use.
|
|
//
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Class: CImplAry
|
|
//
|
|
// Purpose: Base implementation of all the dynamic array classes.
|
|
//
|
|
// Interface:
|
|
//
|
|
// Deref Returns a pointer to an element of the array;
|
|
// should only be used by derived classes. Use the
|
|
// type-safe methods operator[] or Item() instead.
|
|
//
|
|
// GetAlloced Get number of elements allocated
|
|
//
|
|
// Members: _c Current size of the array
|
|
// _pv Buffer storing the elements
|
|
//
|
|
// Note: The CImplAry class only supports arrays of elements
|
|
// whose size is less than 128.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
|
|
class CImplAry
|
|
{
|
|
friend class CImplPtrAry;
|
|
|
|
private:
|
|
DECLARE_MEMALLOC_NEW_DELETE();
|
|
public:
|
|
~CImplAry();
|
|
inline int Size() const { return _c; } // UNIX: long->int for min() macro
|
|
inline void SetSize(int c) { _c = c; }
|
|
inline operator void *() { return PData(); }
|
|
void DeleteAll();
|
|
|
|
// BUGBUG -- This method should be protected, but I don't want to convert
|
|
// existing code that uses it. (lylec)
|
|
void * Deref(size_t cb, int i);
|
|
|
|
#if DBG == 1
|
|
BOOL _fCheckLock ; // If set with TraceTag CImplAryLock then any change
|
|
// (addition or deletion to the DataAry will generate an assert.
|
|
|
|
void LockCheck(BOOL fState)
|
|
{ _fCheckLock = fState; }
|
|
#else
|
|
void LockCheck(BOOL)
|
|
{ }
|
|
#endif
|
|
|
|
NO_COPY(CImplAry);
|
|
|
|
protected:
|
|
|
|
// Methods which are wrapped by inline subclass methods
|
|
|
|
CImplAry();
|
|
|
|
HRESULT EnsureSize(size_t cb, long c);
|
|
HRESULT Grow(size_t cb, int c);
|
|
HRESULT AppendIndirect(size_t cb, void * pv, void ** ppvPlaced=NULL);
|
|
HRESULT InsertIndirect(size_t cb, int i, void * pv);
|
|
int FindIndirect(size_t cb, void *);
|
|
|
|
void Delete(size_t cb, int i);
|
|
BOOL DeleteByValueIndirect(size_t cb, void *pv);
|
|
void DeleteMultiple(size_t cb, int start, int end);
|
|
|
|
HRESULT CopyAppend(size_t cb, const CImplAry& ary, BOOL fAddRef);
|
|
HRESULT Copy(size_t cb, const CImplAry& ary, BOOL fAddRef);
|
|
HRESULT CopyIndirect(size_t cb, int c, void * pv, BOOL fAddRef);
|
|
|
|
ULONG GetAlloced(size_t cb);
|
|
|
|
HRESULT EnumElements(
|
|
size_t cb,
|
|
REFIID iid,
|
|
void ** ppv,
|
|
BOOL fAddRef,
|
|
BOOL fCopy = TRUE,
|
|
BOOL fDelete = TRUE);
|
|
|
|
HRESULT EnumVARIANT(
|
|
size_t cb,
|
|
VARTYPE vt,
|
|
IEnumVARIANT ** ppenum,
|
|
BOOL fCopy = TRUE,
|
|
BOOL fDelete = TRUE);
|
|
|
|
inline BOOL UsingStackArray()
|
|
{ return _fDontFree; }
|
|
|
|
UINT GetStackSize()
|
|
{ Assert(_fStack);
|
|
return *(UINT*)((BYTE*)this + sizeof(CImplAry)); }
|
|
void * GetStackPtr()
|
|
{ Assert(_fStack);
|
|
return (void*)((BYTE*)this + sizeof(CImplAry) + sizeof(int)); }
|
|
|
|
unsigned long _fStack :1 ; // Set if we're a stack-based array.
|
|
unsigned long _fDontFree :1 ; // Cleared if _pv points to alloced memory.
|
|
unsigned long _c :30 ; // Count of elements
|
|
|
|
void * _pv;
|
|
|
|
inline void * & PData() { return _pv; }
|
|
};
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Member: CImplAry::CImplAry
|
|
//
|
|
//+------------------------------------------------------------------------
|
|
inline
|
|
CImplAry::CImplAry()
|
|
{
|
|
memset(this, 0, sizeof(CImplAry));
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Member: CImplAry::Deref
|
|
//
|
|
// Synopsis: Returns a pointer to the i'th element of the array. This
|
|
// method is normally called by type-safe methods in derived
|
|
// classes.
|
|
//
|
|
// Arguments: i
|
|
//
|
|
// Returns: void *
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
inline void *
|
|
CImplAry::Deref(size_t cb, int i)
|
|
{
|
|
Assert(i >= 0);
|
|
Assert(ULONG( i ) < GetAlloced(cb));
|
|
return ((BYTE *) PData()) + i * cb;
|
|
}
|
|
|
|
//+------------------------------------------------------------------------
|
|
//
|
|
// Class: CImplPtrAry (ary)
|
|
//
|
|
// Purpose: Subclass used for arrays of pointers. In this case, the
|
|
// element size is known to be sizeof(void *). Normally, the
|
|
// CPtrAry template is used to define a specific concrete
|
|
// implementation of this class, to hold a specific type of
|
|
// pointer.
|
|
//
|
|
// See documentation above for use.
|
|
//
|
|
//-------------------------------------------------------------------------
|
|
|
|
class CImplPtrAry : public CImplAry
|
|
{
|
|
protected:
|
|
DECLARE_MEMALLOC_NEW_DELETE();
|
|
|
|
CImplPtrAry() : CImplAry() {};
|
|
|
|
HRESULT Append(void * pv);
|
|
HRESULT Insert(int i, void * pv);
|
|
int Find(void * pv);
|
|
BOOL DeleteByValue(void *pv);
|
|
|
|
HRESULT CopyAppend(const CImplAry& ary, BOOL fAddRef);
|
|
HRESULT Copy(const CImplAry& ary, BOOL fAddRef);
|
|
HRESULT CopyIndirect(int c, void * pv, BOOL fAddRef);
|
|
|
|
|
|
public:
|
|
|
|
HRESULT ClearAndReset();
|
|
|
|
HRESULT EnsureSize(long c);
|
|
|
|
HRESULT Grow(int c);
|
|
|
|
void Delete(int i);
|
|
void DeleteMultiple(int start, int end);
|
|
|
|
void ReleaseAll();
|
|
void ReleaseAndDelete(int idx);
|
|
};
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CDataAry
|
|
//
|
|
// Purpose: This template class declares a concrete derived class
|
|
// of CImplAry.
|
|
//
|
|
// See documentation above for use.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template <class ELEM>
|
|
class CDataAry : public CImplAry
|
|
{
|
|
public:
|
|
DECLARE_MEMALLOC_NEW_DELETE();
|
|
|
|
CDataAry() : CImplAry() { }
|
|
operator ELEM *() { return (ELEM *)PData(); }
|
|
CDataAry(const CDataAry &);
|
|
|
|
ELEM & Item(int i) { return *(ELEM*)Deref(sizeof(ELEM), i); }
|
|
|
|
HRESULT EnsureSize(long c)
|
|
{ return CImplAry::EnsureSize(sizeof(ELEM), c); }
|
|
HRESULT Grow(int c)
|
|
{ return CImplAry::Grow(sizeof(ELEM), c); }
|
|
HRESULT AppendIndirect(ELEM * pe, ELEM ** ppePlaced=NULL)
|
|
{ return CImplAry::AppendIndirect(sizeof(ELEM), (void*)pe, (void**)ppePlaced); }
|
|
ELEM * Append()
|
|
{ ELEM * pElem; return AppendIndirect( NULL, & pElem ) ? NULL : pElem; }
|
|
HRESULT InsertIndirect(int i, ELEM * pe)
|
|
{ return CImplAry::InsertIndirect(sizeof(ELEM), i, (void*)pe); }
|
|
int FindIndirect(ELEM * pe)
|
|
{ return CImplAry::FindIndirect(sizeof(ELEM), (void*)pe); }
|
|
|
|
void Delete(int i)
|
|
{ CImplAry::Delete(sizeof(ELEM), i); }
|
|
BOOL DeleteByValueIndirect(ELEM *pe)
|
|
{ return CImplAry::DeleteByValueIndirect(sizeof(ELEM), (void*)pe); }
|
|
void DeleteMultiple(int start, int end)
|
|
{ CImplAry::DeleteMultiple(sizeof(ELEM), start, end); }
|
|
|
|
HRESULT CopyAppend(const CDataAry<ELEM>& ary, BOOL fAddRef)
|
|
{ return CImplAry::Copy(sizeof(ELEM), ary, fAddRef); }
|
|
HRESULT Copy(const CDataAry<ELEM>& ary, BOOL fAddRef)
|
|
{ return CImplAry::Copy(sizeof(ELEM), ary, fAddRef); }
|
|
HRESULT CopyIndirect(int c, ELEM * pv, BOOL fAddRef)
|
|
{ return CImplAry::CopyIndirect(sizeof(ELEM), c, (void*)pv, fAddRef); }
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CPtrAry
|
|
//
|
|
// Purpose: This template class declares a concrete derived class
|
|
// of CImplPtrAry.
|
|
//
|
|
// See documentation above for use.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template <class ELEM>
|
|
class CPtrAry : public CImplPtrAry
|
|
{
|
|
public:
|
|
DECLARE_MEMALLOC_NEW_DELETE();
|
|
|
|
CPtrAry() : CImplPtrAry() { Assert(sizeof(ELEM) == sizeof(void*)); }
|
|
operator ELEM *() { return (ELEM *)PData(); }
|
|
CPtrAry(const CPtrAry &);
|
|
|
|
ELEM & Item(int i) { return *(ELEM*)Deref(sizeof(ELEM), i); }
|
|
|
|
HRESULT Append(ELEM e)
|
|
{ return CImplPtrAry::Append((void*)e); }
|
|
HRESULT Insert(int i, ELEM e)
|
|
{ return CImplPtrAry::Insert(i, (void*)e); }
|
|
BOOL DeleteByValue(ELEM e)
|
|
{ return CImplPtrAry::DeleteByValue((void*)e); }
|
|
int Find(ELEM e)
|
|
{ return CImplPtrAry::Find((void*)e); }
|
|
|
|
HRESULT CopyAppend(const CPtrAry<ELEM>& ary, BOOL fAddRef)
|
|
{ return CImplPtrAry::Copy(ary, fAddRef); }
|
|
HRESULT Copy(const CPtrAry<ELEM>& ary, BOOL fAddRef)
|
|
{ return CImplPtrAry::Copy(ary, fAddRef); }
|
|
HRESULT CopyIndirect(int c, ELEM *pe, BOOL fAddRef)
|
|
{ return CImplPtrAry::CopyIndirect(c, (void*)pe, fAddRef); }
|
|
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CStackDataAry
|
|
//
|
|
// Purpose: Declares a CDataAry that has initial storage on the stack.
|
|
// N elements are declared on the stack, and the array will
|
|
// grow dynamically beyond that if necessary.
|
|
//
|
|
// See documentation above for use.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template <class ELEM, int N>
|
|
class CStackDataAry : public CDataAry<ELEM>
|
|
{
|
|
public:
|
|
DECLARE_MEMALLOC_NEW_DELETE();
|
|
|
|
CStackDataAry() : CDataAry<ELEM>()
|
|
{
|
|
_cStack = N;
|
|
_fStack = TRUE;
|
|
_fDontFree = TRUE;
|
|
PData() = (void *) & _achTInit;
|
|
}
|
|
|
|
protected:
|
|
int _cStack; // Must be first data member.
|
|
char _achTInit[N*sizeof(ELEM)];
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CStackPtrAry
|
|
//
|
|
// Purpose: Same as CStackDataAry except for pointer types.
|
|
//
|
|
// See documentation above for use.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
template <class ELEM, int N>
|
|
class CStackPtrAry : public CPtrAry<ELEM>
|
|
{
|
|
public:
|
|
DECLARE_MEMALLOC_NEW_DELETE();
|
|
|
|
CStackPtrAry() : CPtrAry<ELEM>()
|
|
{
|
|
_cStack = N;
|
|
_fStack = TRUE;
|
|
_fDontFree = TRUE;
|
|
PData() = (void *) & _achTInit;
|
|
}
|
|
|
|
protected:
|
|
int _cStack; // Must be first data member.
|
|
char _achTInit[N*sizeof(ELEM)];
|
|
};
|
|
|