windows-nt/Source/XPSP1/NT/inetsrv/query/h/dynarray.hxx
2020-09-26 16:20:57 +08:00

944 lines
22 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 1998.
//
// File: DYNARRAY.HXX
//
// Contents: Dynamic Array Template
//
// Classes: CDynArray
// CCountedDynArray
// CCountedIDynArray
// CDynArrayInPlace
// CDynArrayInPlaceNST
// CDynStackInPlace
//
// History: 20-Jan-92 AmyA Created
// 05-Feb-92 BartoszM Converted to macro
// 19-Jun-92 KyleP Moved to Common
// 06-Jan-93 AmyA Split into CDynArray and CDynStack
// 17-Oct-94 BartoszM Converted to template
// 10-Mar-98 KLam Added index operator to CCountedDynArray
//
//----------------------------------------------------------------------------
#pragma once
#include <new.h> // Global placement ::operator new
#define arraySize 16
//+---------------------------------------------------------------------------
// Class: CDynArray
//
// Purpose: Template used to hold dynamically sized arrays of objects
//
// History: 19-Aug-98 KLam Added this header
//
//+---------------------------------------------------------------------------
template<class CItem> class CDynArray
{
public:
CDynArray(unsigned size = arraySize);
void SetExactSize( unsigned size )
{
Free();
if ( 0 != size )
{
_size = size;
_aItem = new CItem *[_size];
RtlZeroMemory( _aItem, _size*sizeof(CItem *) );
}
}
CDynArray( CDynArray<CItem> & src );
~CDynArray();
void Add(CItem *newItem, unsigned position);
unsigned Size () const {return _size;}
CItem * Get (unsigned position) const;
CItem * GetItem( unsigned position ) const
{
// unlike Get(), no range-checking is done in free builds
Win4Assert( position < _size );
return _aItem[position];
}
void Clear();
void Free()
{
Clear();
delete _aItem;
_aItem = 0;
_size = 0;
}
CItem * Acquire (unsigned position);
CItem * & operator[]( unsigned position ) const
{
Win4Assert( position < _size );
return _aItem[position];
}
CItem ** GetPointer() const { return _aItem; }
CItem ** AcquireAll()
{
CItem **ppTemp = _aItem;
_size = 0;
_aItem = 0;
return ppTemp;
}
protected:
//
// _size **must** come before _aItem. See the copy constructor below
// and remember the order of member initialization...
//
unsigned _size;
CItem ** _aItem;
};
#define DECL_DYNARRAY( CMyDynArray, CItem )\
typedef CDynArray<CItem> CMyDynArray;
#define IMPL_DYNARRAY( CMyDynArray, CItem )
template<class CItem> CDynArray<CItem>::CDynArray(unsigned size)
: _size( size ), _aItem( 0 )
{
if ( 0 != _size )
{
_aItem = new CItem *[_size];
RtlZeroMemory( _aItem, _size*sizeof(CItem *) );
}
}
template<class CItem> CDynArray<CItem>::CDynArray( CDynArray<CItem> & src )
: _size( src._size ),
_aItem( src.AcquireAll() )
{
}
template<class CItem> CDynArray<CItem>::~CDynArray()
{
Clear();
delete _aItem;
}
template<class CItem> void CDynArray<CItem>::Clear()
{
for (unsigned i=0; i < _size; i++) {
delete _aItem[i];
_aItem[i] = 0;
}
}
template<class CItem> CItem* CDynArray<CItem>::Acquire(unsigned position)
{
CItem *tmp = Get(position);
if (tmp) _aItem[position] = 0;
return tmp;
}
template<class CItem> void CDynArray<CItem>::Add(CItem *newItem, unsigned position)
{
if (position >= _size)
{
unsigned newsize = _size * 2;
if ( newsize == 0 )
newsize = arraySize;
for( ; position>=newsize; newsize*=2);
CItem **aNew = new CItem *[newsize];
memcpy( aNew,
_aItem,
_size * sizeof( CItem *) );
RtlZeroMemory( aNew + _size,
(newsize-_size)*sizeof(CItem *) );
delete _aItem;
_aItem = aNew;
_size = newsize;
}
Win4Assert( _aItem[position] == 0 );
_aItem[position] = newItem;
}
template<class CItem> CItem* CDynArray<CItem>::Get(unsigned position) const
{
if ( position >= _size )
return(0);
return _aItem[position];
}
//+---------------------------------------------------------------------------
// Class: CCountedDynArray
//
// Purpose: Template used to hold dynamically sized arrays of objects with a count
//
// History: 19-Aug-98 KLam Added this header
//
//+---------------------------------------------------------------------------
template<class CItem> class CCountedDynArray: public CDynArray<CItem>
{
public:
CCountedDynArray(unsigned size = arraySize)
: CDynArray<CItem>( size ),
_cItem( 0 )
{
}
void Add(CItem *newItem, unsigned position)
{
CDynArray<CItem>::Add( newItem, position );
if ( position + 1 > _cItem )
_cItem = position + 1;
}
CItem * AcquireAndShrink(unsigned position)
{
XPtr<CItem> xItem( Acquire(position) );
if ( 0 != _cItem && position < (_cItem-1) )
{
Add( Acquire(_cItem-1) , position );
}
return xItem.Acquire();
}
CItem * AcquireAndShrinkAndPreserveOrder(unsigned position)
{
XPtr<CItem> xItem( Acquire(position) );
if ( 0 != _cItem && position < (_cItem-1) )
{
for ( unsigned i = position; i < (_cItem-1); i++ )
Add( Acquire(i+1) , i );
}
return xItem.Acquire();
}
unsigned Count() const { return _cItem; }
void Clear()
{
CDynArray<CItem>::Clear();
_cItem = 0;
}
void Free()
{
CDynArray<CItem>::Free();
_cItem = 0;
}
CItem * Acquire (unsigned position)
{
if ( position == (_cItem - 1) )
_cItem--;
return CDynArray<CItem>::Acquire( position );
}
CItem * & operator[]( unsigned position ) const
{
Win4Assert( position < _cItem );
return _aItem[position];
}
protected:
unsigned _cItem;
};
//+---------------------------------------------------------------------------
// Class: CCountedIDynArray
//
// Purpose: Maintains an array of interface pointers
//
// History: 12-Mar-98 KLam Added this header
// 12-Mar-98 KLam Added AddRef and Destructor does not assert
// released items have a ref count of 0
//
// Notes:
// The class assumes that the creator of the interface pointer has passed
// ownership (and therefore the original reference count) to this object.
// When the object is destroyed it releases each of the interface pointers
// maintained by the object.
// If you want the interfaces in this array to exist beyond the lifespan
// of this class then you must AddRef each of those interface pointers.
// Array can be sparse.
//+---------------------------------------------------------------------------
template<class CItem> class CCountedIDynArray: public CCountedDynArray<CItem>
{
public:
CCountedIDynArray(unsigned size = arraySize)
: CCountedDynArray<CItem>( size )
{
}
~CCountedIDynArray()
{
Release();
for ( unsigned i = 0; i < _size; i++ )
_aItem[ i ] = 0;
}
int Release(); // Calls Release on each interface
void ReleaseAndShrink(); // Calls Release on each interface and packs array
void AddRef(); // Calls AddRef on each interface
void Free()
{
Release();
CCountedDynArray<CItem>::Free();
}
private:
void Clear(); // not a valid method on interfaces.
};
template<class CItem> void CCountedIDynArray<CItem>::AddRef()
{
for ( unsigned i=0; i < _cItem; i++ )
if ( 0 != _aItem[i] )
_aItem[i]->AddRef();
}
// Note: Could make the array sparse(r).
// Value returned could be less than or equal to Count().
template<class CItem> int CCountedIDynArray<CItem>::Release()
{
int cItems = 0;
for (unsigned i=0; i < _cItem; i++)
{
if ( 0 != _aItem[i] )
{
if ( 0 == _aItem[i]->Release() )
{
_aItem[i] = 0;
if ( i == _cItem - 1 )
_cItem--;
}
else
++cItems;
}
}
return cItems;
}
// Note: Packs the array and preserves the order
template<class CItem> void CCountedIDynArray<CItem>::ReleaseAndShrink()
{
unsigned i=0;
while ( i < _cItem )
{
if ( 0 != _aItem[i] && 0 == _aItem[i]->Release() )
{
// This method will decrement _cItem
AcquireAndShrinkAndPreserveOrder(i);
}
else
i++;
}
}
//+---------------------------------------------------------------------------
// Class: CDynArrayInPlace
//
// Purpose: Identical to CDynArray except array objects are stored in place,
// instead of storing an array of pointers.
//
// History: 19-Aug-98 KLam Added this header
//
// Note: This reduces memory allocations, but does not work for objects
// with destructors.
//
//+---------------------------------------------------------------------------
template<class CItem> class CDynArrayInPlace
{
public:
CDynArrayInPlace(unsigned size);
CDynArrayInPlace();
CDynArrayInPlace( CDynArrayInPlace const & src );
CDynArrayInPlace( CDynArrayInPlace const & src, unsigned size );
~CDynArrayInPlace();
void Add( const CItem &newItem, unsigned position);
void Insert(const CItem& newItem, unsigned position);
void Remove (unsigned position);
unsigned Size () const {return _size;}
CItem& Get (unsigned position) const;
CItem * Get() { return _aItem; }
void Clear();
unsigned Count() const { return _count; }
void SetSize(unsigned position)
{
if (position >= _size)
_GrowToSize(position);
}
void SetExactSize( unsigned size )
{
Clear();
if ( 0 != size )
{
_size = size;
_aItem = new CItem [_size];
RtlZeroMemory( _aItem, _size * sizeof(CItem) );
}
}
void Shrink()
{
// make size == count, to save memory
if ( 0 == _count )
{
Clear();
}
else if ( _count != _size )
{
CItem * p = new CItem [_count];
_size = _count;
RtlCopyMemory( p, _aItem, _count * sizeof CItem );
delete (BYTE *) _aItem;
_aItem = p;
}
}
CItem* Acquire ()
{
CItem *temp = _aItem;
_aItem = 0;
_count = 0;
_size = 0;
return temp;
}
void Duplicate( CDynArrayInPlace<CItem> & aFrom )
{
Clear();
if ( 0 != aFrom.Count() )
{
_size = _count = aFrom.Count();
_aItem = new CItem [_size];
memcpy( _aItem, aFrom._aItem, _size * sizeof( CItem ) );
}
}
CItem & operator[]( unsigned position )
{
if ( position >= _count )
{
if ( position >= _size )
_GrowToSize( position );
_count = position + 1;
}
return _aItem[position];
}
CItem & operator[]( unsigned position ) const
{
Win4Assert( position < _count );
return _aItem[position];
}
CItem const * GetPointer() { return _aItem; }
unsigned SizeOfInUse() const { return sizeof CItem * Count(); }
protected:
void _GrowToSize( unsigned position );
CItem * _aItem;
unsigned _size;
unsigned _count;
};
#define DECL_DYNARRAY_INPLACE( CMyDynArrayInPlace, CItem )\
typedef CDynArrayInPlace<CItem> CMyDynArrayInPlace;
#define IMPL_DYNARRAY_INPLACE( CMyDynArrayInPlace, CItem )
template<class CItem> CDynArrayInPlace<CItem>::CDynArrayInPlace(unsigned size)
: _size(size), _count(0), _aItem( 0 )
{
if ( 0 != size )
{
_aItem = new CItem [_size];
RtlZeroMemory( _aItem, _size * sizeof(CItem) );
}
}
template<class CItem> CDynArrayInPlace<CItem>::CDynArrayInPlace()
: _size(0), _count(0), _aItem(0)
{
}
template<class CItem> CDynArrayInPlace<CItem>::CDynArrayInPlace( CDynArrayInPlace const & src )
: _size( src._size ),
_count( src._count )
{
_aItem = new CItem [_size];
RtlCopyMemory( _aItem, src._aItem, _size * sizeof(_aItem[0]) );
}
template<class CItem> CDynArrayInPlace<CItem>::CDynArrayInPlace(
CDynArrayInPlace const & src,
unsigned size )
: _size( size ),
_count( src._count )
{
// this constructor is useful if the size should be larger than the
// # of items in the source array
Win4Assert( _size >= _count );
_aItem = new CItem [_size];
RtlCopyMemory( _aItem, src._aItem, _count * sizeof CItem );
}
template<class CItem> CDynArrayInPlace<CItem>::~CDynArrayInPlace()
{
delete [] _aItem;
}
template<class CItem> void CDynArrayInPlace<CItem>::Clear()
{
delete [] _aItem;
_aItem = 0;
_size = 0;
_count = 0;
}
template<class CItem> void CDynArrayInPlace<CItem>::_GrowToSize( unsigned position )
{
Win4Assert( position >= _size );
unsigned newsize = _size * 2;
if ( newsize == 0 )
newsize = arraySize;
for( ; position >= newsize; newsize *= 2)
continue;
CItem *aNew = new CItem [newsize];
if (_size > 0)
{
memcpy( aNew,
_aItem,
_size * sizeof( CItem ) );
}
RtlZeroMemory( aNew + _size,
(newsize-_size) * sizeof(CItem) );
delete (BYTE*) _aItem;
_aItem = aNew;
_size = newsize;
}
template<class CItem> void CDynArrayInPlace<CItem>::Add(const CItem &newItem,
unsigned position)
{
if (position >= _count)
{
if (position >= _size)
_GrowToSize( position );
_count = position + 1;
}
_aItem[position] = newItem;
}
template<class CItem> CItem& CDynArrayInPlace<CItem>::Get(unsigned position) const
{
Win4Assert( position < _count );
return _aItem[position];
}
template<class CItem> void CDynArrayInPlace<CItem>::Insert(const CItem& newItem, unsigned pos)
{
Win4Assert(pos <= _count);
Win4Assert(_count <= _size);
if (_count == _size)
{
unsigned newsize;
if ( _size == 0 )
newsize = arraySize;
else
newsize = _size * 2;
CItem *aNew = new CItem [newsize];
memcpy( aNew,
_aItem,
pos * sizeof( CItem ) );
memcpy( aNew + pos + 1,
_aItem + pos,
(_count - pos) * sizeof(CItem));
delete (BYTE *) _aItem;
_aItem = aNew;
_size = newsize;
}
else
{
memmove ( _aItem + pos + 1,
_aItem + pos,
(_count - pos) * sizeof(CItem));
}
_aItem[pos] = newItem;
_count++;
}
template<class CItem> void CDynArrayInPlace<CItem>::Remove(unsigned pos)
{
Win4Assert(pos < _count);
Win4Assert(_count <= _size);
if (pos < _count - 1)
{
memmove ( _aItem + pos,
_aItem + pos + 1,
(_count - pos - 1) * sizeof(CItem));
}
RtlZeroMemory( _aItem + _count - 1, sizeof(CItem) );
_count--;
if (_count == 0)
{
delete (BYTE*) _aItem;
_aItem = 0;
_size = 0;
}
}
//+-------------------------------------------------------------------------
//
// Class: CDynArrayInPlaceNST
//
// Purpose: DynArrayInPlace for NonSimpleTypes
//
// History: 4-June-98 dlee Created
//
// Notes: This isn't for every class in the world; use with care.
//
//--------------------------------------------------------------------------
template<class T> class CDynArrayInPlaceNST
{
public:
CDynArrayInPlaceNST(unsigned size) :
_size( size ), _count( 0 ), _aItem( 0 )
{
if ( 0 != size )
{
unsigned cb = _size * sizeof T;
_aItem = (T *) new BYTE[ cb ];
// Just in case...
RtlZeroMemory( _aItem, cb );
// Call all the default constructors
for ( unsigned i = 0; i < _size; i++ )
new( & _aItem[i] ) T;
}
}
CDynArrayInPlaceNST() : _count(0), _size(0), _aItem(0) {}
~CDynArrayInPlaceNST() { Clear(); }
unsigned Size () const { return _size; }
unsigned Count() const { return _count; }
T const * GetPointer() { return _aItem; }
unsigned SizeOfInUse() const { return sizeof T * Count(); }
void Add( const T &newItem, unsigned position)
{
if (position >= _count)
{
if (position >= _size)
_GrowToSize( position );
_count = position + 1;
}
_aItem[position] = newItem;
}
void Insert( const T& newItem, unsigned position )
{
Win4Assert(pos <= _count);
Win4Assert(_count <= _size);
if ( _count == _size )
{
unsigned newsize;
if ( _size == 0 )
newsize = arraySize;
else
newsize = _size * 2;
unsigned cb = newSize * sizeof T;
T * aNew = (T *) new BYTE[ cb ];
RtlZeroMemory( & aNew[ newSize - 1 ], sizeof T );
new( & _aItem[ newSize - 1 ]) T;
memcpy( aNew,
_aItem,
pos * sizeof T );
memcpy( aNew + pos + 1,
_aItem + pos,
(_count - pos) * sizeof T );
delete [] (BYTE *) _aItem;
_aItem = aNew;
_size = newsize;
}
else
{
memmove( _aItem + pos + 1,
_aItem + pos,
(_count - pos) * sizeof T );
}
RtlCopyMemory( _aItem[pos], newItem, sizeof T );
_count++;
}
#if 0 // probably broken...
void Remove (unsigned position)
{
Win4Assert(pos < _count);
Win4Assert(_count <= _size);
if (pos < _count - 1)
memmove ( _aItem + pos,
_aItem + pos + 1,
(_count - pos - 1) * sizeof T );
RtlZeroMemory( _aItem + _count - 1, sizeof T );
_count--;
if ( 0 == _count )
{
delete [] (BYTE*) _aItem;
_aItem = 0;
_size = 0;
}
}
#endif
T & Get (unsigned position) const
{
Win4Assert( position < _count );
return _aItem[ position ];
}
void Clear()
{
for ( unsigned i = 0; i < _size; i++ )
_aItem[i].~T();
delete [] (BYTE*) _aItem;
_aItem = 0;
_size = 0;
_count = 0;
}
void SetSize(unsigned position)
{
if (position >= _size)
_GrowToSize(position);
}
void SetExactSize( unsigned size )
{
Clear();
if ( 0 != size )
{
_size = size;
unsigned cb = _size * sizeof T;
_aItem = (T *) new BYTE[ cb ];
// Just in case...
RtlZeroMemory( _aItem, cb );
// Call all the default constructors
for ( unsigned i = 0; i < _size; i++ )
new( & _aItem[i] ) T;
}
}
void Shrink()
{
// make size == count, to save memory
if ( 0 == _count )
{
Clear();
}
else if ( _count != _size )
{
unsigned cb = _size * sizeof T;
T * p = (T *) new BYTE[ cb ];
_size = _count;
RtlCopyMemory( p, _aItem, _count * sizeof T );
delete [] (BYTE *) _aItem;
_aItem = p;
}
}
T * Acquire()
{
T *temp = _aItem;
_aItem = 0;
_count = 0;
_size = 0;
return temp;
}
void Duplicate( CDynArrayInPlaceNST<T> & aFrom )
{
Clear();
if ( 0 != aFrom.Count() )
{
_size = _count = aFrom.Count();
unsigned cb = _size * sizeof T;
_aItem = (T *) new BYTE[ cb ];
memcpy( _aItem, aFrom._aItem, _size * sizeof T );
}
}
T & operator[]( unsigned position )
{
if ( position >= _count )
{
if ( position >= _size )
_GrowToSize( position );
_count = position + 1;
}
return _aItem[position];
}
T & operator[]( unsigned position ) const
{
Win4Assert( position < _count );
return _aItem[position];
}
protected:
void _GrowToSize( unsigned position )
{
Win4Assert( position >= _size );
unsigned newSize = _size * 2;
if ( newSize == 0 )
newSize = arraySize;
for( ; position >= newSize; newSize *= 2)
continue;
unsigned cb = newSize * sizeof T;
T *aNew = (T *) new BYTE[ cb ];
if (_size > 0)
memcpy( aNew,
_aItem,
_size * sizeof T );
RtlZeroMemory( aNew + _size,
(newSize - _size) * sizeof T );
for ( unsigned i = _size; i < newSize; i++ )
new( & aNew[ i ] ) T;
delete [] (BYTE*) _aItem;
_aItem = aNew;
_size = newSize;
}
T * _aItem;
unsigned _size;
unsigned _count;
};
//+---------------------------------------------------------------------------
//
// Class: CDynStackInPlace
//
// Purpose: Identical to CDynArrayInPlace except array is accessed as a stack.
// Unlike CDynStack because the actual objects are stored, not
// pointers. Useful for simple types.
//
// History: 19-Aug-98 KLam Added this header
//
//+---------------------------------------------------------------------------
template<class T> class CDynStackInPlace : public CDynArrayInPlace<T>
{
public:
CDynStackInPlace(unsigned size = arraySize);
~CDynStackInPlace() {};
void Push(T newItem);
unsigned Count () const { return _stackSize; }
T & Pop();
private:
unsigned _stackSize;
};
template<class T> CDynStackInPlace<T>::CDynStackInPlace(unsigned size) :
CDynArrayInPlace<T>(size),
_stackSize(0)
{
}
template<class T> void CDynStackInPlace<T>::Push(T newItem)
{
Add( newItem, _stackSize );
_stackSize++;
}
template<class T> T & CDynStackInPlace<T>::Pop()
{
Win4Assert( _stackSize > 0 );
_stackSize--;
return Get(_stackSize);
}