593 lines
13 KiB
C++
593 lines
13 KiB
C++
//+------------------------------------------------------------------------
|
|
//
|
|
// 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);
|
|
}
|