windows-nt/Source/XPSP1/NT/shell/lib/generic/dynamicarray.cpp
2020-09-26 16:20:57 +08:00

532 lines
16 KiB
C++

// --------------------------------------------------------------------------
// 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: <none>
//
// 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: <none>
//
// Returns: <none>
//
// 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);
_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<char*>(_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<char*>(_pvArray) + (_iElementSize * iElementIndex), static_cast<char*>(_pvArray) + (_iElementSize * (iElementIndex + 1)), iMoveSize);
}
ZeroMemory(static_cast<char*>(_pvArray) + (_iElementSize * (_iArraySize - 1)), _iElementSize);
--_iArraySize;
}
else
{
status = STATUS_INVALID_PARAMETER;
}
}
return(status);
}
// --------------------------------------------------------------------------
// CDynamicArray::GetCount
//
// Arguments: <none>
//
// 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<char*>(_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<char*>(_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<char*>(_pvArray) + (_iElementSize * i), i);
}
}
return(status);
}
// --------------------------------------------------------------------------
// CDynamicPointerArray::CDynamicPointerArray
//
// Arguments: <none>
//
// Returns: <none>
//
// 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: <none>
//
// Returns: <none>
//
// 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<void**>(_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<void**>(_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: <none>
//
// Returns: <none>
//
// 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: <none>
//
// Returns: <none>
//
// 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<CCountedObject**>(_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<CCountedObject**>(_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);
}