//+------------------------------------------------------------------------ // // File: formsary.cxx // // Contents: Generic dynamic array class // // Classes: CImplAry // //------------------------------------------------------------------------- #include // 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); }