windows-nt/Source/XPSP1/NT/windows/richedit/re30/array.cpp
2020-09-26 16:20:57 +08:00

307 lines
6.4 KiB
C++

/*
* @doc INTERNAL
*
* @module ARRAY.C -- Generic Array Implementation |
*
* Original Author: <nl>
* Christian Fortini
*
* History: <nl>
* 6/25/95 alexgo Cleanup and Commented
*
* Copyright (c) 1995-1997, Microsoft Corporation. All rights reserved.
*/
#include "_common.h"
#include "_array.h"
ASSERTDATA
const int celGrow = 8;
//
// Invariant support
//
#define DEBUG_CLASSNAME CArrayBase
#include "_invar.h"
// =================================== CArrayBase ================================================
#ifdef DEBUG
/*
* CArrayBase::Invariant()
*
* @mfunc Tests the array state to make sure it is valid. DEBUG only
*
* @rdesc TRUE if the tests succeed, FALSE otherwise
*/
BOOL CArrayBase::Invariant() const
{
Assert(_cbElem > 0);
if(!_prgel)
{
Assert(_cel == 0);
Assert(_celMax == 0);
// We go ahead and return a value here so that
// this function can be executed in the "watch"
// window of various debuggers
if(_cel || _celMax)
return FALSE;
}
else
{
Assert(_celMax > 0 );
Assert(_cel <= _celMax);
if(_celMax == 0 || _cel > _celMax)
return FALSE;
}
return TRUE;
}
/*
* CArrayBase::Elem(iel)
*
* @mfunc Returns a pointer to the element indexed by <p iel>
*
* @rdesc A pointer to the element indexed by <p iel>. This pointer may
* be cast to a pointer of the appropriate element type.
*/
void* CArrayBase::Elem(
LONG iel) const //@parm Index to use
{
_TEST_INVARIANT_
// This can arise with empty froms^3 controls.
// Review (keithcu) Why did this start happening in Richedit 3?
if (!_cel)
return NULL;
AssertSz(iel == 0 || (iel > 0 && iel < _cel),
"CArrayBase::Elem() - Index out of range");
return _prgel + iel * _cbElem;
}
#endif
/*
* CArrayBase::CArrayBase
*
* @mfunc Constructor
*/
CArrayBase::CArrayBase(
LONG cbElem) //@parm Size of an individual array element
{
_prgel = NULL;
_cel = 0;
_celMax = 0;
_cbElem = cbElem;
}
/*
* CArrayBase::ArAdd
*
* @mfunc Adds <p celAdd> elements to the end of the array.
*
* @rdesc A pointer to the start of the new elements added. If non-NULL,
* <p pielIns> will be set to the index at which elements were added.
*
* We grow in steps of celGrow when small and exponentially when large.
*/
void* CArrayBase::ArAdd(
LONG celAdd, //@parm Count of elements to add
LONG *pielIns) //@parm Out parm for index of first element added
{
_TEST_INVARIANT_
char *pel;
if(_cel + celAdd > _celMax) // need to grow
{
LONG celNew = max(celAdd, celGrow) + _cel / 16;
pel = (char*)PvReAlloc(_prgel, (_celMax + celNew) * _cbElem);
if(!pel)
return NULL;
_prgel = pel;
_celMax += celNew;
}
pel = _prgel + _cel * _cbElem;
ZeroMemory(pel, celAdd * _cbElem);
if(pielIns)
*pielIns = _cel;
_cel += celAdd;
return pel;
}
/*
* CArrayBase::ArInsert (iel, celIns)
*
* @mfunc Inserts <p celIns> new elements at index <p iel>
*
* @rdesc A pointer to the newly inserted elements. Will be NULL on
* failure.
*/
void* CArrayBase::ArInsert(
LONG iel, //@parm Index at which to insert
LONG celIns) //@parm Count of elements to insert
{
char *pel;
_TEST_INVARIANT_
AssertSz(iel <= _cel, "CArrayBase::Insert() - Insert out of range");
if(iel >= _cel)
return ArAdd(celIns, NULL);
if(_cel + celIns > _celMax) // need to grow
{
AssertSz(_prgel, "CArrayBase::Insert() - Growing a non existent array !");
LONG celNew = max(celIns, celGrow) + _cel / 16;
pel = (char*)PvReAlloc(_prgel, (_celMax + celNew) * _cbElem);
if(!pel)
{
TRACEERRORSZ("CArrayBase::Insert() - Couldn't realloc line array");
return NULL;
}
_prgel = pel;
_celMax += celNew;
}
pel = _prgel + iel * _cbElem;
if(iel < _cel) // Nove Elems up to make room for new ones
MoveMemory(pel + celIns*_cbElem, pel, (_cel - iel)*_cbElem);
_cel += celIns;
return pel;
}
/*
* CArrayBase::Remove
*
* @mfunc Removes the <p celFree> elements from the array starting at index
* <p ielFirst>. If <p celFree> is negative, then all elements after
* <p ielFirst> are removed.
*
* @rdesc nothing
*/
void CArrayBase::Remove(
LONG ielFirst, //@parm Index at which elements should be removed
LONG celFree) //@parm Count of elements to remove.
{
char *pel;
_TEST_INVARIANT_
if(celFree < 0)
celFree = _cel - ielFirst;
AssertSz(ielFirst + celFree <= _cel, "CArrayBase::Free() - Freeing out of range");
if(_cel > ielFirst + celFree)
{
pel = _prgel + ielFirst * _cbElem;
MoveMemory(pel, pel + celFree * _cbElem,
(_cel - ielFirst - celFree) * _cbElem);
}
_cel -= celFree;
if(_cel < _celMax - celGrow - _cel / 16)
{
// Shrink array
_celMax = max(_cel, celGrow);
_prgel = (char*)PvReAlloc(_prgel, _celMax * _cbElem);
Assert(_prgel);
}
}
/*
* CArrayBase::Clear
*
* @mfunc Clears the entire array, potentially deleting all of the memory
* as well.
*
* @rdesc nothing
*/
void CArrayBase::Clear(
ArrayFlag flag) //@parm Indicates what should be done with the memory
//in the array. One of AF_DELETEMEM or AF_KEEPMEM
{
_TEST_INVARIANT_
if( flag == AF_DELETEMEM )
{
FreePv(_prgel);
_prgel = NULL;
_celMax = 0;
}
else if (_prgel)
{
_celMax = min(celGrow, _celMax);
_prgel = (char*) PvReAlloc(_prgel, celGrow * _cbElem);
}
_cel = 0;
}
/*
* CArrayBase::Replace
*
* @mfunc Replaces the <p celRepl> elements at index <p ielRepl> with the
* contents of the array specified by <p par>. If <p celRepl> is negative,
* then the entire contents of <p this> array starting at <p ielRepl> should
* be replaced.
*
* @rdesc Returns TRUE on success, FALSE otherwise.
*/
BOOL CArrayBase::Replace(
LONG ielRepl, //@parm index at which replacement should occur
LONG celRepl, //@parm number of elements to replace (may be
// negative, indicating that all
CArrayBase *par) //@parm array to use as the replacement source
{
_TEST_INVARIANT_
LONG celMove = 0;
LONG celIns = par->Count();
if (celRepl < 0)
celRepl = _cel - ielRepl;
AssertSz(ielRepl + celRepl <= _cel, "CArrayBase::ArReplace() - Replacing out of range");
celMove = min(celRepl, celIns);
if (celMove > 0)
{
MoveMemory(Elem(ielRepl), par->Elem(0), celMove * _cbElem);
celIns -= celMove;
celRepl -= celMove;
ielRepl += celMove;
}
Assert(celIns >= 0);
Assert(celRepl >= 0);
Assert(celIns + celMove == par->Count());
if(celIns > 0)
{
Assert(celRepl == 0);
void *pelIns = ArInsert (ielRepl, celIns);
if (!pelIns)
return FALSE;
MoveMemory(pelIns, par->Elem(celMove), celIns * _cbElem);
}
else if(celRepl > 0)
Remove (ielRepl, celRepl);
return TRUE;
}