// -------------------------------------------------------------------------- // Module Name: DynamicArray.cpp // // Copyright (c) 1999-2000, Microsoft Corporation // // This file contains related classes to manage dynamic arrays. The array is // grown as required but never shrunk. The base class handles struct arrays. // Subclasses handle special cases of these arrays (such as pointer or // CCountedObject arrays). // // History: 1999-11-16 vtan created // 2000-02-01 vtan moved from Neptune to Whistler // -------------------------------------------------------------------------- #include "StandardHeader.h" #include "DynamicArray.h" #include "CountedObject.h" // -------------------------------------------------------------------------- // CDynamicArray::CDynamicArray // // Arguments: iElementSize = Size of each array element. // // Returns: // // Purpose: Constructor for CDynamicArray. Stores the element size and // initializes the memory used to NULL. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- CDynamicArray::CDynamicArray (int iElementSize) : _iElementSize(iElementSize), _iArraySize(0), _pvArray(NULL) { ASSERTMSG(iElementSize > 0, "Cannot have negative or zero length element size in CDynamicArray::CDynamicArray"); } // -------------------------------------------------------------------------- // CDynamicArray::~CDynamicArray // // Arguments: // // Returns: // // Purpose: Destructor for CDynamicArray. Frees the memory used by the // array. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- CDynamicArray::~CDynamicArray (void) { ReleaseMemory(_pvArray); } // -------------------------------------------------------------------------- // CDynamicArray::Add // // Arguments: pvData = Pointer to the data to copy to the array. // // Returns: NTSTATUS // // Purpose: Allocates memory for the element to be added to the array. If // there is no memory block it allocates an initial block. If // there isn't enough memory in the block to hold the next // element then it allocates a new larger block. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicArray::Add (const void *pvData) { NTSTATUS status; static const int DEFAULT_ELEMENTS_PER_ALLOCATE = 16; status = STATUS_NO_MEMORY; // If no array exists then allocate the first // block of memory for this array. if (_pvArray == NULL) { _iArraySize = 0; _iArrayAllocatedSize = DEFAULT_ELEMENTS_PER_ALLOCATE; _pvArray = LocalAlloc(LPTR, _iElementSize * _iArrayAllocatedSize); } // If the array exists but the limit of the allocated size has // been reached then allocate a new block, copy the current // block contents and fall thru. if (_pvArray != NULL) { if (_iArraySize == _iArrayAllocatedSize) { void *pvNewArray; pvNewArray = LocalAlloc(LPTR, _iElementSize * (_iArrayAllocatedSize + DEFAULT_ELEMENTS_PER_ALLOCATE)); if (pvNewArray != NULL) { _iArrayAllocatedSize += DEFAULT_ELEMENTS_PER_ALLOCATE; CopyMemory(pvNewArray, _pvArray, _iElementSize * _iArraySize); (HLOCAL)LocalFree(_pvArray); _pvArray = pvNewArray; } } // Otherwise there is a spare slot in the array. Copy the // data to the array. Increment the array size. if (_iArraySize < _iArrayAllocatedSize) { CopyMemory(static_cast(_pvArray) + (_iElementSize * _iArraySize), pvData, _iElementSize); ++_iArraySize; status = STATUS_SUCCESS; } } return(status); } // -------------------------------------------------------------------------- // CDynamicArray::Remove // // Arguments: iElementIndex = Index of the element to remove. // // Returns: NTSTATUS // // Purpose: Removes the element from the array. Slides down all the // members but does not reduce the size of the memory block used // by the array. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicArray::Remove (int iElementIndex) { NTSTATUS status; status = STATUS_SUCCESS; if (_pvArray != NULL) { // Make sure the index is valid. if (iElementIndex < _iArraySize) { int iMoveSize; // Determine the amount of bytes to move when deleting this // element and move the memory. Don't resize the array when // shrinking. Just leave it alone. iMoveSize = _iElementSize * (_iArraySize - iElementIndex - 1); ASSERTMSG(iMoveSize >= 0, "Negative move memory size in CDynamicArray::Remove"); if (iMoveSize > 0) { MoveMemory(static_cast(_pvArray) + (_iElementSize * iElementIndex), static_cast(_pvArray) + (_iElementSize * (iElementIndex + 1)), iMoveSize); } ZeroMemory(static_cast(_pvArray) + (_iElementSize * (_iArraySize - 1)), _iElementSize); --_iArraySize; } else { status = STATUS_INVALID_PARAMETER; } } return(status); } // -------------------------------------------------------------------------- // CDynamicArray::GetCount // // Arguments: // // Returns: int // // Purpose: Returns the number of elements in the array. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- int CDynamicArray::GetCount (void) const { return(_iArraySize); } // -------------------------------------------------------------------------- // CDynamicArray::Get // // Arguments: pvData = Pointer to memory to receive element. // iElementIndex = Index of element to retrieve in array. // // Returns: NTSTATUS // // Purpose: Copies the data for the specified element by index to the // block of memory given. No checks for access violations. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicArray::Get (void *pvData, int iElementIndex) { NTSTATUS status; if ((_pvArray != NULL) && (iElementIndex < _iArraySize)) { CopyMemory(pvData, static_cast(_pvArray) + (_iElementSize * iElementIndex), _iElementSize); status = STATUS_SUCCESS; } else { status = STATUS_INVALID_PARAMETER; } return(status); } // -------------------------------------------------------------------------- // CDynamicArray::Set // // Arguments: pvData = Pointer to memory to receive element. // iElementIndex = Index of element to retrieve in array. // // Returns: NTSTATUS // // Purpose: Copies the data for the specified element by index from the // block of memory given. No checks for access violations. // // History: 2000-11-11 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicArray::Set (const void* pvData, int iElementIndex) { NTSTATUS status; status = STATUS_SUCCESS; if (_pvArray != NULL) { if (iElementIndex < _iArraySize) { CopyMemory(static_cast(_pvArray) + (_iElementSize * iElementIndex), pvData, _iElementSize); } else { status = STATUS_INVALID_PARAMETER; } } return(status); } // -------------------------------------------------------------------------- // CDynamicArray::Iterate // // Arguments: pDynamicArrayCallback = Interface containing callback. // // Returns: NTSTATUS // // Purpose: Iterate the elements of the array. Call the callback function // specified in the interface and give it a pointer to the // element and the index. Adhere to the NTSTATUS returned from // the callback and terminate on an unsuccessful result. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicArray::Iterate (CDynamicArrayCallback *pDynamicArrayCallback) { NTSTATUS status; status = STATUS_SUCCESS; if (_pvArray != NULL) { int i; for (i = _iArraySize - 1; NT_SUCCESS(status) && (i >= 0); --i) { status = pDynamicArrayCallback->Callback(static_cast(_pvArray) + (_iElementSize * i), i); } } return(status); } // -------------------------------------------------------------------------- // CDynamicPointerArray::CDynamicPointerArray // // Arguments: // // Returns: // // Purpose: Constructor for CDynamicPointerArray. All elements of this // class are pointers that are allocated with LocalAlloc. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- CDynamicPointerArray::CDynamicPointerArray (void) : CDynamicArray(sizeof(void*)) { } // -------------------------------------------------------------------------- // CDynamicPointerArray::~CDynamicPointerArray // // Arguments: // // Returns: // // Purpose: Destructor for CDynamicPointerArray. Walk the entire array // and free each pointer in the array before allowing the base // class destructor to release the memory allocated for the // actual array itself. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- CDynamicPointerArray::~CDynamicPointerArray (void) { if (_pvArray != NULL) { int i; for (i = _iArraySize - 1; i >= 0; --i) { ReleaseMemory(static_cast(_pvArray)[i]); } } } // -------------------------------------------------------------------------- // CDynamicPointerArray::Add // // Arguments: pvData = Pointer to add to the array. // // Returns: NTSTATUS // // Purpose: Add the given pointer to the array. The pointer is passed in // to this function not a pointer to the pointer. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicPointerArray::Add (const void *pvData) { return(CDynamicArray::Add(&pvData)); } // -------------------------------------------------------------------------- // CDynamicPointerArray::Remove // // Arguments: iElementIndex = Index of the element to remove. // // Returns: NTSTATUS // // Purpose: Releases the memory occupied by the element and then removes // the element from the array. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicPointerArray::Remove (int iElementIndex) { if ((_pvArray != NULL) && (iElementIndex < _iArraySize)) { ReleaseMemory(static_cast(_pvArray)[iElementIndex]); } return(CDynamicArray::Remove(iElementIndex)); } // -------------------------------------------------------------------------- // CDynamicPointerArray::Get // // Arguments: iElementIndex = Index of the element to get. // // Returns: void* // // Purpose: Returns the address of the given element in the array. This // applies only to pointer arrays. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- void* CDynamicPointerArray::Get (int iElementIndex) { void* pvData; if (!NT_SUCCESS(CDynamicArray::Get(&pvData, iElementIndex))) { pvData = NULL; } return(pvData); } // -------------------------------------------------------------------------- // CDynamicCountedObjectArray::CDynamicCountedObjectArray // // Arguments: // // Returns: // // Purpose: Constructor for the CDynamicCountedObjectArray. All elements // should be a subclass of CCountedObject in some way. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- CDynamicCountedObjectArray::CDynamicCountedObjectArray (void) : CDynamicArray(sizeof(CCountedObject*)) { } // -------------------------------------------------------------------------- // CDynamicCountedObjectArray::~CDynamicCountedObjectArray // // Arguments: // // Returns: // // Purpose: Destructor for CDynamicCountedObjectArray. Walk the entire // array and release each CCountedObject in the array before // allowing the base class destructor to release the memory // allocated for the actual array itself. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- CDynamicCountedObjectArray::~CDynamicCountedObjectArray (void) { if (_pvArray != NULL) { int i; for (i = _iArraySize - 1; i >= 0; --i) { reinterpret_cast(_pvArray)[i]->Release(); } } } // -------------------------------------------------------------------------- // CDynamicCountedObjectArray::Add // // Arguments: pvData = CCountedObject* to add to the array. // // Returns: NTSTATUS // // Purpose: Adds the CCountedObject* to the array. Calls // CCountedObject::AddRef to incremenet the reference count on // the object. If the object cannot be added the reference is // released. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicCountedObjectArray::Add (CCountedObject *pvData) { NTSTATUS status; pvData->AddRef(); status = CDynamicArray::Add(&pvData); if (!NT_SUCCESS(status)) { pvData->Release(); } return(status); } // -------------------------------------------------------------------------- // CDynamicCountedObjectArray::Remove // // Arguments: iElementIndex = Index of the element to remove. // // Returns: NTSTATUS // // Purpose: Releases the reference held on the CCountedObject* and then // removes the element from the array. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- NTSTATUS CDynamicCountedObjectArray::Remove (int iElementIndex) { if ((_pvArray != NULL) && (iElementIndex < _iArraySize)) { reinterpret_cast(_pvArray)[iElementIndex]->Release(); } return(CDynamicArray::Remove(iElementIndex)); } // -------------------------------------------------------------------------- // CDynamicCountedObjectArray::Get // // Arguments: iElementIndex = Index of the element to get. // // Returns: CCountedObject* // // Purpose: Returns the address of the given element in the array. This // applies only to CCountedObject* arrays. This does NOT call // CCountedObject::AddRef on the returned pointer. // // History: 1999-11-16 vtan created // -------------------------------------------------------------------------- CCountedObject* CDynamicCountedObjectArray::Get (int iElementIndex) { CCountedObject* pObject; pObject = NULL; (NTSTATUS)CDynamicArray::Get(&pObject, iElementIndex); return(pObject); }