|
|
//+------------------------------------------------------------------------
//
// File: formsary.cxx
//
// Contents: Generic dynamic array class
//
// Classes: CImplAry
//
//-------------------------------------------------------------------------
#include <headers.hxx>
// CImplAry class
//+------------------------------------------------------------------------
//
// Member: CImplAry::~CImplAry
//
// Synopsis: Resizeable array destructor. Frees storage allocated for the
// array.
//
//-------------------------------------------------------------------------
CImplAry::~CImplAry( ) { if (!UsingStackArray()) { MemFree(PData()); } }
//+---------------------------------------------------------------------------
//
// Member: CImplAry::GetAlloced, public
//
// Synopsis: Returns the number of bytes that have been allocated.
//
// Arguments: [cb] -- Size of each element
//
// Notes: For the CStackAry classes the value returned is _cStack*cb if
// we're still using the stack-allocated array.
//
//----------------------------------------------------------------------------
ULONG CImplAry::GetAlloced(size_t cb) { if (UsingStackArray()) { return GetStackSize() * cb; } else { return MemGetSize(PData()); } }
//+------------------------------------------------------------------------
//
// Member: CImplAry::EnsureSize
//
// Synopsis: Ensures that the array is at least the given size. That is,
// if EnsureSize(c) succeeds, then (c-1) is a valid index. Note
// that the array maintains a separate count of the number of
// elements logically in the array, which is obtained with the
// Size/SetSize methods. The logical size of the array is never
// larger than the allocated size of the array.
//
// Arguments: cb Element size
// c New allocated size for the array.
//
// Returns: HRESULT
//
//-------------------------------------------------------------------------
HRESULT CImplAry::EnsureSize ( size_t cb, long c ) { HRESULT hr = S_OK; unsigned long cbAlloc;
if (UsingStackArray() && (long)(c * cb) <= (long)GetAlloced(cb)) goto Cleanup;
Assert( c >= 0 );
cbAlloc = ((c < 8) ? c : ((c + 7) & ~7)) * cb;
if (UsingStackArray() || (((unsigned long) c > ((_c < 8) ? _c : ((_c + 7) & ~7))) && cbAlloc > MemGetSize(PData()))) { Assert(!_fCheckLock && "CDataAry changing while CImplAryLock is on");
if (UsingStackArray()) { //
// We have to switch from the stack-based array to an allocated
// one, so allocate the memory and copy the data over.
//
void * pbDataOld = PData(); int cbOld = GetAlloced( cb );
PData() = MemAlloc( cbAlloc );
if (!PData()) { hr = E_OUTOFMEMORY; goto Cleanup; }
memcpy( PData(), pbDataOld, cbOld ); } else { hr = MemRealloc( (void **) & PData(), cbAlloc );
if (hr) goto Cleanup; }
_fDontFree = FALSE; }
Cleanup:
RRETURN( hr ); }
//+---------------------------------------------------------------------------
//
// Member: CImplAry::Grow, public
//
// Synopsis: Ensures enough memory is allocated for c elements and then
// sets the size of the array to that much.
//
// Arguments: [cb] -- Element Size
// [c] -- Number of elements to grow array to.
//
// Returns: HRESULT
//
//----------------------------------------------------------------------------
HRESULT CImplAry::Grow(size_t cb, int c) { HRESULT hr = EnsureSize(cb, c); if (!hr) { SetSize(c); }
RRETURN(hr); }
//+------------------------------------------------------------------------
//
// Member: CImplAry::AppendIndirect
//
// Synopsis: Appends the given element to the end of the array,
// incrementing the array's logical size, and growing the
// array's allocated size if necessary. Note that the element
// is passed with a pointer, rather than directly.
//
// Arguments: cb Element size
// pv Pointer to the element to be appended
// ppvPlaced Pointer to the element that's inside the array
//
// Returns: HRESULT
//
// Notes: If pv is NULL, the element is appended and initialized to
// zero.
//
//-------------------------------------------------------------------------
HRESULT CImplAry::AppendIndirect(size_t cb, void * pv, void ** ppvPlaced) { HRESULT hr;
hr = EnsureSize(cb, _c + 1); if (hr) RRETURN(hr);
if (ppvPlaced) { *ppvPlaced = Deref(cb, _c); }
if (!pv) { memset(Deref(cb, _c), 0, cb); } else { memcpy(Deref(cb, _c), pv, cb); }
_c++;
return NOERROR; }
//+------------------------------------------------------------------------
//
// Member: CImplAry::Delete
//
// Synopsis: Removes the i'th element of the array, shuffling all
// elements that follow one slot towards the beginning of the
// array.
//
// Arguments: cb Element size
// i Element to delete
//
//-------------------------------------------------------------------------
void CImplAry::Delete(size_t cb, int i) { Assert(i >= 0); Assert(i < (int)_c);
Assert(!_fCheckLock && "CDataAry changing while CImplAryLock is on");
memmove(((BYTE *) PData()) + (i * cb), ((BYTE *) PData()) + ((i + 1) * cb), (_c - i - 1) * cb);
_c--; }
//+------------------------------------------------------------------------
//
// Member: CImplAry::DeleteByValueIndirect
//
// Synopsis: Removes the element matching the given value.
//
// Arguments: cb Element size
// pv Element to delete
//
// Returuns: True if found & deleted.
//
//-------------------------------------------------------------------------
BOOL CImplAry::DeleteByValueIndirect(size_t cb, void *pv) { int i = FindIndirect(cb, pv); if (i >= 0) { Delete(cb, i); return TRUE; } else { return FALSE; } }
//+------------------------------------------------------------------------
//
// Member: CImplAry::DeleteMultiple
//
// Synopsis: Removes a range of elements of the array, shuffling all
// elements that follow the last element being deleted slot
// towards the beginning of the array.
//
// Arguments: cb Element size
// start First element to delete
// end Last element to delete
//
//-------------------------------------------------------------------------
void CImplAry::DeleteMultiple(size_t cb, int start, int end) { Assert((start >= 0) && (end >= 0)); Assert((start < (int)_c) && (end < (int)_c)); Assert(end >= start);
if ((unsigned)end < (_c - 1)) { memmove(((BYTE *) PData()) + (start * cb), ((BYTE *) PData()) + ((end + 1) * cb), (_c - end - 1) * cb); }
_c -= (end - start) + 1; }
//+------------------------------------------------------------------------
//
// Member: CImplAry::DeleteAll
//
// Synopsis: Efficient method for emptying array of any contents
//
//-------------------------------------------------------------------------
void CImplAry::DeleteAll(void) { Assert(!_fCheckLock && "CDataAry changing while CImplAryLock is on");
if (!UsingStackArray()) { MemFree(PData());
if (_fStack) { PData() = GetStackPtr(); _fDontFree = TRUE; } else { PData() = NULL; } }
_c = 0; }
//+------------------------------------------------------------------------
//
// Member: CImplAry::InsertIndirect
//
// Synopsis: Inserts a pointer pv at index i. The element previously at
// index i, and all elements that follow it, are shuffled one
// slot away towards the end of the array.Note that the
// clement is passed with a pointer, rather than directly.
//
// Arguments: cb Element size
// i Index to insert...
// pv ...this pointer at
//
// if pv is NULL then the element is initialized to all zero.
//
//-------------------------------------------------------------------------
HRESULT CImplAry::InsertIndirect(size_t cb, int i, void *pv) { HRESULT hr;
hr = EnsureSize(cb, _c + 1); if (hr) RRETURN(hr);
memmove(((BYTE *) PData()) + ((i + 1) * cb), ((BYTE *) PData()) + (i * cb), (_c - i ) * cb);
if (!pv) { memset(Deref(cb, i), 0, cb); } else { memcpy(Deref(cb, i), pv, cb); } _c++; return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Member: CImplAry::FindIndirect
//
// Synopsis: Finds an element of a non-pointer array.
//
// Arguments: cb The size of the element.
// pv Pointer to the element.
//
// Returns: The index of the element if found, otherwise -1.
//
//----------------------------------------------------------------------------
int CImplAry::FindIndirect(size_t cb, void * pv) { int i; void * pvT;
pvT = PData(); for (i = _c; i > 0; i--) { if (!memcmp(pv, pvT, cb)) return _c - i;
pvT = (char *) pvT + cb; }
return -1; }
//+---------------------------------------------------------------------------
//
// Member: CImplAry::Copy
//
// Synopsis: Creates a copy from another CImplAry object.
//
// Arguments: ary Object to copy.
// fAddRef Addref the elements on copy?
//
//----------------------------------------------------------------------------
HRESULT CImplAry::Copy(size_t cb, const CImplAry& ary, BOOL fAddRef) { RRETURN(CopyIndirect(cb, ary._c, ((CImplAry *)&ary)->PData(), fAddRef)); }
//+------------------------------------------------------------------------
//
// Member: CImplAry::CopyIndirect
//
// Synopsis: Fills a forms array from a C-style array of raw data
//
// Arguments: [cb]
// [c]
// [pv]
// [fAddRef]
//
// Returns: HRESULT
//
//-------------------------------------------------------------------------
HRESULT CImplAry::CopyIndirect(size_t cb, int c, void * pv, BOOL fAddRef) { IUnknown ** ppUnk;
if (pv == PData()) return S_OK;
DeleteAll(); if (pv) { if (EnsureSize(cb, c)) RRETURN(E_OUTOFMEMORY);
memcpy(PData(), pv, c * cb); }
_c = c;
if (fAddRef) { for (ppUnk = (IUnknown **) PData(); c > 0; c--, ppUnk++) { (*ppUnk)->AddRef(); } }
return S_OK; }
HRESULT CImplPtrAry::ClearAndReset() { // BUGBUG why does this function reallocate memory, rather than
// just memset'ing to 0? (chrisz)
// BUGBUG -- Do not use this method! Use DeleteAll to clear the array.
Assert(!PData());
PData() = NULL; HRESULT hr = EnsureSize(_c); _c = 0;
RRETURN(hr); }
//+------------------------------------------------------------------------
//
// Member: CImplPtrAry::*
//
// Synopsis: CImplPtrAry elements are always of size four.
// The following functions encode this knowledge.
//
//-------------------------------------------------------------------------
HRESULT CImplPtrAry::EnsureSize(long c) { return CImplAry::EnsureSize(sizeof(void *), c); }
HRESULT CImplPtrAry::Grow(int c) { return CImplAry::Grow(sizeof(void *), c); }
HRESULT CImplPtrAry::Append(void * pv) { return CImplAry::AppendIndirect(sizeof(void *), &pv); }
HRESULT CImplPtrAry::Insert(int i, void * pv) { return CImplAry::InsertIndirect(sizeof(void *), i, &pv); }
int CImplPtrAry::Find(void * pv) { int i; void ** ppv;
for (i = 0, ppv = (void **) PData(); (unsigned)i < _c; i++, ppv++) { if (pv == *ppv) return i; }
return -1; }
void CImplPtrAry::Delete(int i) { CImplAry::Delete(sizeof(void *), i); }
BOOL CImplPtrAry::DeleteByValue(void *pv) { int i = Find(pv); if (i >= 0) { CImplAry::Delete(sizeof(void *), i); return TRUE; } else { return FALSE; } }
void CImplPtrAry::DeleteMultiple(int start, int end) { CImplAry::DeleteMultiple(sizeof(void*), start, end); }
void CImplPtrAry::ReleaseAndDelete(int idx) { IUnknown * pUnk;
Assert(idx < (int)_c);
// grab element at idx
pUnk = ((IUnknown **) PData())[idx];
Delete(idx);
if (pUnk) (pUnk)->Release(); }
void CImplPtrAry::ReleaseAll(void) { int i; IUnknown ** ppUnk;
for (i = 0, ppUnk = (IUnknown **) PData(); (unsigned)i < _c; i++, ppUnk++) { if (*ppUnk) (*ppUnk)->Release(); }
DeleteAll(); }
HRESULT CImplPtrAry::CopyIndirect(int c, void * pv, BOOL fAddRef) { return CImplAry::CopyIndirect(sizeof(void *), c, pv, fAddRef); }
HRESULT CImplPtrAry::Copy(const CImplAry& ary, BOOL fAddRef) { return CImplAry::Copy(sizeof(void *), ary, fAddRef); }
|