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.
 
 
 
 
 
 

301 lines
8.0 KiB

/**************************************************************************\
*
* Copyright (c) 1998 Microsoft Corporation
*
* Module Name:
*
* dynarray.hpp
*
* Abstract:
*
* Dynamic array template classes. See DynamicArrays.doc in the Specs
* directory.
*
* DynArray is a container which keeps its contents in a contiguous buffer,
* reallocating memory as necessary. It accepts an optional initial
* allocation, which is used unless it is too small to accommodate the
* elements.
*
* DynArrayIA is a cosmetic wrapper which encapsulates the intial allocation,
* allowing the dynamic array to be treated like a normal class.
*
* Revision History:
*
* 12/02/1998 davidx
* Created it.
* 02/26/1999 agodfrey
* Revamped it to use an implementation class (DynArrayImpl).
* Now the template part of it can compile to nothing, or be small enough
* to inline efficiently, so that using the template with many different
* types doesn't cause code bloat.
*
* Also, I added a version (DynArrayIA) which makes using an initial
* allocation much easier.
*
* Notes:
*
* 12/02/1998 davidx
* Changes from the previous version in gdiplus prototype:
* + getData: Use &dynarr[index] instead.
* + increaseCount: Use addMultiple instead (2nd variation).
* + replace: Use dynarr[index] = newItem.
* + attachData: Use dynarr.replaceWith(dynarr2).
* + constructor: No longer takes initialCapacity, use ReserveSpace instead
* + new constructor: Takes a stack array which is used for buffer (faster).
*
* 02/26/1999 agodfrey
* + Use the 'implementation class' to avoid code bloat for out-of-line
* functions.
* + GetCapacity: Unused, not useful - removed.
* + Reset: Added 'shrink' flag (default true). If it's false, Reset sets the
* count to zero but doesn't free the memory. This is preferable to
* SetCount(0).
* + Made ShrinkToSize() reuse the initial allocation. This also makes the
* growing and shrinking logic simpler - 'no initial allocation' is treated
* like an initial allocation of size zero (at memory location 'NULL').
*
\**************************************************************************/
#ifndef _DYNARRAY_HPP
#define _DYNARRAY_HPP
template <class T> class DynArray : public DynArrayImpl
{
public:
// Default allocation step size
enum
{
DEFAULT_STEPSIZE = 512
};
// Constructor
//
// initalAllocation - the initial allocation, which can be global,
// static or dynamic memory (or NULL)
// allocSize - size of the initial allocation
// (0 if there is none)
// stepSize - number of elements added each time the buffer grows
DynArray(
T *initialAllocation,
UINT allocSize,
UINT stepSize = DEFAULT_STEPSIZE
):
DynArrayImpl(initialAllocation, allocSize, stepSize)
{
}
// Constructor (no initial allocation)
//
// stepSize - number of elements added each time the buffer grows
DynArray(UINT stepSize = DEFAULT_STEPSIZE):
DynArrayImpl(NULL, 0, stepSize)
{
}
// Destructor
~DynArray()
{
if (DataBuffer != InitialAllocation)
{
GpFree(DataBuffer);
}
}
// Change the step size to the specified value
VOID SetStepSize(UINT stepSize = DEFAULT_STEPSIZE)
{
ASSERT(stepSize > 0);
StepSize = stepSize;
}
// Return a pointer to the array data
// NOTE: We intentionally avoid type conversion operator here
// to reduce the chances for confusion.
T *GetDataBuffer() const
{
return static_cast<T *>(DataBuffer);
}
// Index operator
T &operator[](INT n) const
{
ASSERT(n >= 0 && (UINT)n < Count);
return GetDataBuffer()[n];
}
// First/last element of the array
T &First() const
{
ASSERT(Count > 0);
return GetDataBuffer()[0];
}
T &Last() const
{
ASSERT(Count > 0);
return GetDataBuffer()[Count-1];
}
// Number of elements in the array
INT GetCount() const
{
return Count;
}
// Reset the dynamic array to empty state
//
// shrink - If FALSE, don't free the current buffer.
VOID Reset(BOOL shrink=TRUE)
{
Count = 0;
if (shrink)
{
ShrinkToSize();
}
}
// Shrink the dynamic array capacity to be just big enough
// for the number of existing elements in the array.
//
// This reuses the initial allocation if possible.
VOID ShrinkToSize()
{
DynArrayImpl::ShrinkToSize(sizeof(T));
}
// Add a new element to the end of the dynamic array
GpStatus Add(const T& newItem)
{
return DynArrayImpl::AddMultiple(sizeof(T), 1, &newItem);
}
// Add multiple items to the end of the dynamic array
GpStatus AddMultiple(const T* newItems, INT n)
{
return DynArrayImpl::AddMultiple(sizeof(T), n, newItems);
}
// Another variation of addMultiple above
//
// In this case, the data for the new elements are
// not available. Instead, we'll do the following:
// (1) reserve the space for additional elements
// (2) increase the Count by the number of additional elements
// (3) return a pointer to the first new elements
T *AddMultiple(INT n)
{
return static_cast<T *>(DynArrayImpl::AddMultiple(sizeof(T), n));
}
// Detach the data buffer from the dynamic array
// Cannot be used if there is an initial allocation
T *DetachData()
{
return static_cast<T *>(DynArrayImpl::DetachData());
}
// Detatch the buffer from another array, and set this array
// to point to it. NOTE: This modifies the other array.
VOID ReplaceWith(DynArray<T> *dynarr)
{
if (DataBuffer != InitialAllocation)
{
GpFree(DataBuffer);
}
Count = dynarr->Count;
Capacity = dynarr->Capacity;
DataBuffer = dynarr->DetachData();
}
// More dangerous interface:
//
// These functions are alternatives to Add/AddMultiple.
// They can be used to reduce overhead, but you have to know what
// you're doing.
//
// AdjustCount/SetCount - modify the count directly, without growing or
// shrinking the array.
// ReserveSpace - grow the buffer, but don't actually add any elements to
// the array.
VOID AdjustCount(UINT addElts)
{
Count += addElts;
}
VOID SetCount(UINT count)
{
Count = count;
}
GpStatus ReserveSpace(UINT newElements)
{
return Grow(sizeof(T), newElements);
}
// !! This is added as a hack to allow bitwise cloning
// of DynArray types.
GpStatus RenewDataBuffer()
{
void *oldDataBuffer = DataBuffer;
void *oldInitialAllocation = InitialAllocation;
InitialAllocation = NULL;
AllocSize = 0;
DataBuffer = (VOID*) malloc(Capacity*sizeof(T));
memcpy(DataBuffer, oldDataBuffer, Capacity*sizeof(T));
return Ok;
}
};
// DynArrayIA: A version of DynArray which encapsulates the initial allocation.
//
// For example:
//
// DynArrayIA<MyType, 10> array(16);
//
// This declares a DynArray of MyType objects, with an initial allocation of
// 10 elements, and a step size of 16. Such a declaration can be used on
// the stack or in another object.
template <class T, int ALLOCSIZE> class DynArrayIA : public DynArray<T>
{
public:
// Constructor
//
// stepSize - number of elements added each time the buffer grows
DynArrayIA(UINT stepSize = DEFAULT_STEPSIZE):
DynArray<T>(InitialAllocationBuffer, ALLOCSIZE, stepSize)
{
}
private:
T InitialAllocationBuffer[ALLOCSIZE];
};
#endif // !_DYNARRAY_HPP