You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
494 lines
12 KiB
494 lines
12 KiB
/**************************************************************************\
|
|
*
|
|
* Copyright (c) 1998 Microsoft Corporation
|
|
*
|
|
* Module Name:
|
|
*
|
|
* Dynamic array implementation class
|
|
*
|
|
* Abstract:
|
|
*
|
|
* This is the class which implements the dynamic array.
|
|
* It is used by the wrapper template classes DynArray and DynArrayIA.
|
|
*
|
|
* Created:
|
|
*
|
|
* 2/18/1999 agodfrey
|
|
*
|
|
* 6/10/1999 t-wehunt
|
|
* + Added AddMultipleAt and DeleteMultipleAt methods.
|
|
* + Fixed a problem in ShrinkToSize that caused elements to potentially
|
|
* be lost.
|
|
* 8/16/2000 bhouse
|
|
* + Changed cpacity growth to be exponential
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hpp"
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* DynArrayImpl constructor
|
|
*
|
|
* Arguments:
|
|
*
|
|
* initialAllocation - initial allocation, or NULL
|
|
* allocSize - size of the initial allocation
|
|
* count - initial count
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 2/25/1999 agodfrey
|
|
*
|
|
\**************************************************************************/
|
|
|
|
DynArrayImpl::DynArrayImpl(
|
|
void *initialAllocation,
|
|
UINT allocSize,
|
|
UINT count
|
|
)
|
|
{
|
|
ASSERT((initialAllocation != NULL) || (allocSize == 0));
|
|
ASSERT(count <= allocSize);
|
|
|
|
DataBuffer = InitialAllocation = initialAllocation;
|
|
Capacity = AllocSize = allocSize;
|
|
Count = count;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Shrink the buffer so that it is just big enough for the items
|
|
* the dynamic array holds.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* eltSize - size of each array element
|
|
*
|
|
* Return Value:
|
|
*
|
|
* NONE
|
|
*
|
|
* Created:
|
|
*
|
|
* 1/18/1999 agodfrey
|
|
* Added code to reuse the initial allocation.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID DynArrayImpl::ShrinkToSize(UINT eltSize)
|
|
{
|
|
ASSERT(Count <= Capacity);
|
|
|
|
if (DataBuffer == InitialAllocation)
|
|
{
|
|
// Since we're shrinking, we know that the current data buffer
|
|
// is big enough.
|
|
|
|
return;
|
|
}
|
|
|
|
if (Count <= AllocSize)
|
|
{
|
|
// The buffer will fit into the initial allocation.
|
|
|
|
GpMemcpy(InitialAllocation,DataBuffer,Count * eltSize);
|
|
GpFree(DataBuffer);
|
|
DataBuffer = InitialAllocation;
|
|
Capacity = AllocSize;
|
|
return;
|
|
}
|
|
|
|
// If we get here, we know that DataBuffer points to dynamic memory,
|
|
// and that Count != 0.
|
|
//
|
|
// The second point is important because GpRealloc(x, 0) returns
|
|
// a pointer to a valid zero-length buffer.
|
|
|
|
void *newbuf = GpRealloc(DataBuffer, Count*eltSize);
|
|
|
|
if (!newbuf)
|
|
{
|
|
// GpRealloc failed. Keep the current allocation
|
|
|
|
WARNING(("ShrinkToSize: GpRealloc failed"));
|
|
return;
|
|
}
|
|
|
|
DataBuffer = newbuf;
|
|
Capacity = Count;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Add space for new elements (if necessary). Does not update Count.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* eltSize - size of each array element
|
|
* newElements - the number of new elements
|
|
* exactSize - no exponential growth, just add required amount
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 1/18/1999 agodfrey
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus DynArrayImpl::Grow(UINT eltSize, UINT newElements, BOOL exactSize)
|
|
{
|
|
UINT newCount = Count + newElements;
|
|
|
|
if (newCount <= Capacity)
|
|
{
|
|
return Ok;
|
|
}
|
|
|
|
UINT capacityIncrement = newCount - Capacity;
|
|
|
|
if (!exactSize)
|
|
{
|
|
capacityIncrement = max(capacityIncrement,
|
|
min(max(Capacity, kMinCapacityGrowth),
|
|
kMaxCapacityGrowth));
|
|
};
|
|
|
|
UINT newCapacity = Capacity + capacityIncrement;
|
|
|
|
void *newbuf;
|
|
|
|
if (DataBuffer == InitialAllocation)
|
|
{
|
|
// Do our first dynamic allocation
|
|
|
|
newbuf = GpMalloc(newCapacity*eltSize);
|
|
|
|
if (newbuf && Count)
|
|
{
|
|
GpMemcpy(newbuf, DataBuffer, Count*eltSize);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Reallocate memory
|
|
|
|
newbuf = GpRealloc(DataBuffer, newCapacity*eltSize);
|
|
}
|
|
|
|
if (!newbuf)
|
|
{
|
|
WARNING(("Grow: alloc failed"));
|
|
|
|
// Aid in tracking down memory failure cases not handled properly
|
|
#if 0
|
|
ASSERT(FALSE);
|
|
#endif
|
|
return OutOfMemory;
|
|
}
|
|
|
|
Capacity = newCapacity;
|
|
DataBuffer = newbuf;
|
|
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Detach the data buffer from the dynamic array.
|
|
* Allocates the buffer to detatch if it is the initial allocation.
|
|
*
|
|
* Return Value:
|
|
*
|
|
* The data buffer
|
|
*
|
|
* Created:
|
|
*
|
|
* 2/25/1999 agodfrey
|
|
* 12/19/2000 asecchia - handle initial allocation by returning a copy.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus DynArrayImpl::DetachData(UINT eltSize, void **buffer)
|
|
{
|
|
void *data = DataBuffer;
|
|
|
|
// Copy the initial allocation if there is one -
|
|
// otherwise we simply use the DataBuffer.
|
|
|
|
if (DataBuffer == InitialAllocation)
|
|
{
|
|
data = GpMalloc(Capacity*eltSize);
|
|
|
|
if (NULL == data)
|
|
{
|
|
*buffer = NULL;
|
|
return OutOfMemory;
|
|
}
|
|
|
|
if (Count)
|
|
{
|
|
GpMemcpy(data, DataBuffer, Count*eltSize);
|
|
}
|
|
}
|
|
|
|
DataBuffer = NULL;
|
|
Count = Capacity = 0;
|
|
|
|
*buffer = data;
|
|
return Ok;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Add new, uninitialized elements, and return a pointer to them.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* eltSize - size of each element
|
|
* newElements - number of new elements
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Pointer to the new space, or NULL on failure
|
|
*
|
|
* Created:
|
|
*
|
|
* 2/25/1999 agodfrey
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void *DynArrayImpl::AddMultiple(UINT eltSize, UINT newElements)
|
|
{
|
|
ASSERT(newElements>0);
|
|
|
|
if (Grow(eltSize, newElements) != Ok)
|
|
return NULL;
|
|
|
|
void *newSpace = static_cast<BYTE *>(DataBuffer) + Count * eltSize;
|
|
Count += newElements;
|
|
|
|
return newSpace;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Add new elements, initializing them with the given data.
|
|
*
|
|
* Arguments:
|
|
*
|
|
* eltSize - size of each element
|
|
* newElements - number of new elements
|
|
* newData - the data to be copied into the new space
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 2/25/1999 agodfrey
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus DynArrayImpl::AddMultiple(
|
|
UINT eltSize,
|
|
UINT newElements,
|
|
const void *newData
|
|
)
|
|
{
|
|
ASSERT(newElements>0);
|
|
|
|
GpStatus status = Grow(eltSize, newElements);
|
|
|
|
if (status == Ok)
|
|
{
|
|
// NOTE: assume T is a shallow data type, i.e.
|
|
// it doesn't contain nested references.
|
|
|
|
GpMemcpy(
|
|
static_cast<BYTE *>(DataBuffer) + Count * eltSize,
|
|
newData,
|
|
newElements * eltSize
|
|
);
|
|
Count += newElements;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
#ifdef USE_OBSOLETE_DYNSORTARRAY
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Add new, uninitialized elements, and return a pointer to them.
|
|
* All data from index on is shift towards the end of the array to make room.
|
|
* CAUTION! could cause a big performance hit if the array is large!
|
|
*
|
|
* Arguments:
|
|
*
|
|
* eltSize - size of each element
|
|
* index - index from which to insert the new elements.
|
|
* newElements - number of new elements
|
|
*
|
|
* Return Value:
|
|
*
|
|
* Pointer to the new space, or NULL on failure
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/10/1999 t-wehunt
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void *DynArrayImpl::AddMultipleAt(
|
|
UINT eltSize,
|
|
UINT index,
|
|
UINT newElements
|
|
)
|
|
{
|
|
ASSERT(newElements>0 && index<=Count);
|
|
|
|
if (Grow(eltSize, newElements) != Ok)
|
|
return NULL;
|
|
|
|
// NOTE: assume T is a shallow data type, i.e.
|
|
// it doesn't contain nested references.
|
|
GpMemmove(
|
|
static_cast<BYTE *>(DataBuffer) + (index + newElements) * eltSize,
|
|
static_cast<BYTE *>(DataBuffer) + index * eltSize,
|
|
(Count - index) * eltSize
|
|
);
|
|
|
|
void *newSpace = static_cast<BYTE *>(DataBuffer) + index * eltSize;
|
|
Count += newElements;
|
|
|
|
return newSpace;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Add new elements, initializing them with the given data.
|
|
* All data from index on is shift towards the end of the array to make room.
|
|
* CAUTION! could cause a big performance hit if the array is large!
|
|
*
|
|
* Arguments:
|
|
*
|
|
* eltSize - size of each element
|
|
* index - index from which to insert the new elements.
|
|
* newElements - number of new elements
|
|
* newData - the data to be copied into the new space
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/10/1999 t-wehunt
|
|
*
|
|
\**************************************************************************/
|
|
|
|
GpStatus DynArrayImpl::AddMultipleAt(
|
|
UINT eltSize,
|
|
UINT index,
|
|
UINT newElements,
|
|
const void *newData
|
|
)
|
|
{
|
|
ASSERT(newElements>0 && index<=Count);
|
|
|
|
GpStatus status = Grow(eltSize, newElements);
|
|
|
|
if (status == Ok)
|
|
{
|
|
// NOTE: assume T is a shallow data type, i.e.
|
|
// it doesn't contain nested references.
|
|
|
|
GpMemmove(
|
|
static_cast<BYTE *>(DataBuffer) + (index + newElements) * eltSize,
|
|
static_cast<BYTE *>(DataBuffer) + index * eltSize,
|
|
(Count - index) * eltSize
|
|
);
|
|
GpMemcpy(
|
|
static_cast<BYTE *>(DataBuffer) + index * eltSize,
|
|
newData,
|
|
newElements * eltSize
|
|
);
|
|
Count += newElements;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
/**************************************************************************\
|
|
*
|
|
* Function Description:
|
|
*
|
|
* Deletes multiple items from the array starting at the index'th position.
|
|
* CAUTION! could cause a big performance hit if the array is large!
|
|
*
|
|
* Arguments:
|
|
*
|
|
* eltSize - size of each element
|
|
* index - index from which to delete the elements.
|
|
* numElements - number of elements to delete
|
|
*
|
|
* Return Value:
|
|
*
|
|
* GpStatus - Ok or failure status
|
|
*
|
|
* Created:
|
|
*
|
|
* 6/10/1999 t-wehunt
|
|
*
|
|
\**************************************************************************/
|
|
|
|
|
|
GpStatus DynArrayImpl::DeleteMultipleAt(
|
|
UINT eltSize,
|
|
UINT index,
|
|
UINT numElements
|
|
)
|
|
{
|
|
ASSERT(numElements>0 && (index+numElements)<=Count);
|
|
|
|
GpMemmove(
|
|
static_cast<BYTE *>(DataBuffer) + index * eltSize,
|
|
static_cast<BYTE *>(DataBuffer) + (index + numElements) * eltSize,
|
|
(Count - (index + numElements)) * eltSize
|
|
);
|
|
Count -= numElements;
|
|
|
|
ShrinkToSize(eltSize);
|
|
|
|
return Ok;
|
|
}
|
|
|
|
#endif
|
|
|