|
|
/*
* @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; }
|