/* * @doc INTERNAL * * @module ARRAY.C -- Generic Array Implementation | * * Original Author: * Christian Fortini * * History: * 6/25/95 alexgo Cleanup and Commented * KeithCu Changed to auto/grow and shrink exponentially * * Copyright (c) 1995-1999, Microsoft Corporation. All rights reserved. */ #include "_common.h" #include "_array.h" ASSERTDATA const int celGrow = 4; // // 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

* * @rdesc A pointer to the element indexed by

. 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_ AssertSz(iel == 0 || (iel > 0 && iel < _cel), "CArrayBase::Elem() - Index out of range"); return _prgel + iel * _cbElem; } #endif /* * CArrayBase::TransferTo * * @mfunc Shallow copy array to passed-in array, and * initialize *this. */ void CArrayBase::TransferTo(CArrayBase &ar) { Assert(ar._cbElem == _cbElem); ar._cel = _cel; ar._celMax = _celMax; ar._prgel = _prgel; _prgel = NULL; _cel = 0; _celMax = 0; } /* * 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

elements to the end of the array. * * @rdesc A pointer to the start of the new elements added. If non-NULL, *

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(!_prgel || _cel + celAdd > _celMax) // need to grow { LONG celNew; if (!_prgel) { _cel = 0; _celMax = 0; } 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

new elements at index

* * @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

elements from the array starting at index *

. If

is negative, then all elements after *

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 LONG celCount = max(_cel, celGrow); char* prgelLocal = (char*)PvReAlloc(_prgel, celCount * _cbElem); if (prgelLocal) { _celMax = celCount; _prgel = prgelLocal; } } } /* * 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_ _cel = 0; if( flag != AF_DELETEMEM && _prgel) { LONG celCount = min(celGrow, _celMax); char *prgelLocal = (char*) PvReAlloc(_prgel, celCount * _cbElem); if (prgelLocal) { _celMax = celCount; _prgel = prgelLocal; return; } } FreePv(_prgel); _prgel = NULL; _celMax = 0; } /* * CArrayBase::Replace * * @mfunc Replaces the

elements at index

with the * contents of the array specified by

. If

is negative, * then the entire contents of

array starting at

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; }