Leaked source code of windows server 2003
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

/**************************************************************************\
*
* 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