DYNARRAY.H

// ----------------------------------------------------------------------------- 
// DynArray.h: Template Class that allows you to make a dynamic array of almost
// any type or class.
//
// Copyright (C) Microsoft Corp. 1986-1996. All Rights Reserved.
// -----------------------------------------------------------------------------

#ifndef _DYNARRAY_H_
#define _DYNARRAY_H_

// -----------------------------------------------------------------------------
// Use this class to create an array of almost any type or class. The exception
// is with classes that have construction that does not initialize all data to
// zero, classes that need destructors, or classes that can not be binary copied.
//
// Once the object is created usage of it is nearly identical to using a regular
// array of that type or class. See example of usage at the end of this file.
//
// NOTE: When passing an object of CDynamicArray< type> as a parameter for a
// variable argument list you must type cast it. This is different usage
// from when the parameter is fixed and the compiler knows the type.
// See and example of this at the very end of this file.
//
// -----------------------------------------------------------------------------

template< class TYPE>
class CDynamicArray
{
public:
// CONSTRUCTOR: Dynamicly creates an array.
CDynamicArray( ULONG nCnt = 0);

// DESTRUCTOR: Frees the memory that was allocated.
~CDynamicArray() {Delete();}

// Returns a pointer to the TYPE by just specifying the object.
operator TYPE*() {return( m_ptr);}

// Frees the memory that was allocated.
void Delete();

// Frees the memory that was allocated and then allocates a new block.
void New( ULONG nCnt);

// Expand the array by nCnt. Return TRUE if it was expanded.
BOOL bExpand( ULONG nCnt);

protected:
TYPE* m_ptr; // Pointer to the array you ordered.
ULONG m_Size; // Number of items allocated.
};

// $--CDynamicArray< TYPE>::CDynamicArray()-------------------------------------
// CONSTRUCTOR: Dynamicly creates an array.
// -----------------------------------------------------------------------------

template< class TYPE>
CDynamicArray< TYPE>::CDynamicArray(
ULONG nCnt) // Initial size of array. It is okay to pass zero.
{
m_ptr = NULL;
m_Size = 0;
New( nCnt);
}

// $--CDynamicArray< TYPE>::Delete()--------------------------------------------
// Frees the memory that was allocated.
// -----------------------------------------------------------------------------

template< class TYPE>
void CDynamicArray< TYPE>::Delete()
{
if( m_ptr)
{
delete [] m_ptr;
m_ptr = NULL;
m_Size = 0;
}
}

// $--CDynamicArray< TYPE>::New()-----------------------------------------------
// Frees the memory that was allocated and then allocates a new block.
// NOTE: If you already had copy of a pointer to this array you must reload it.
// -----------------------------------------------------------------------------

template< class TYPE>
void CDynamicArray< TYPE>::New(
ULONG nCnt) // Initial size of array. It is okay to pass zero.
{
Delete(); // If there was data delete it.
bExpand( nCnt);
}

// $--CDynamicArray< TYPE>::bExpand()-------------------------------------------
// Expand the array by nCnt. Return TRUE if it was expanded.
// NOTE: If you already had copy of a pointer to this array you must reload it.
// -----------------------------------------------------------------------------

template< class TYPE>
BOOL CDynamicArray< TYPE>::bExpand( // RETURNS: TRUE if successful.
ULONG nCnt) // Amount to expand array by.
{
if( !nCnt)
return( TRUE); // It is okay to pass zero.

// Allocate the additonal memory.
TYPE* pNew = new TYPE[ m_Size + nCnt];
if( !pNew)
{ // Could not allocate that much memory.
HR_LOG( E_OUTOFMEMORY);
return( FALSE);
}

// Is this the first allocation?
if( m_ptr)
{ // NO, so copy previous allocation into this block.
memcpy( pNew, m_ptr, m_Size * sizeof( TYPE));
delete [] m_ptr;
}

// Initialize new block of data to zero.
memset( pNew + m_Size, 0, nCnt * sizeof( TYPE));

// Adjust working pointers.
m_ptr = pNew;
m_Size += nCnt;

return( TRUE);
}

// -----------------------------------------------------------------------------

#ifdef _EXAMPLES_
void TestCDynamicArray()
{
CDynamicArray< char> Str( 20); // Construct an array of 20 characters.
CDynamicArray< int> IntArray( 3); // Construct an array of 3 integers.

if( !IntArray || !Str)
return; // Could not allocate memory.

strcpy( Str, "This is a dynamic test.");

IntArray[0] = 1;
IntArray[1] = 2;
IntArray[2] = 3;

IntArray.New( 6); // Free old memory and reallocate 6 integers.
if( !IntArray)
return; // Could not allocate memory.

IntArray[0] = 11;
IntArray[1] = 12;
IntArray[2] = 13;
IntArray[3] = 14;
IntArray[4] = 15;
IntArray[5] = 16;

// Expand array by 4 and bring it to a total size of 10.
if( !IntArray.bExpand( 4))
return; // Could not allocate memory.

IntArray[6] = 17;
IntArray[7] = 18;
IntArray[8] = 19;
IntArray[9] = 20;

CDynamicArray< char> Buf( 100); // Construct an array of 100 characters.
if( !Buf)
return; // Could not allocate memory.

// NOTE: When passing an object of CDynamicArray< type> as a parameter for a
// variable argument list you must either type cast it. This is different
// usage from when the parameter is fixed and the compiler knows the type.
//
// Notice the difference in the way Buf is used and the way Str is used. The
// compiler knows the first parameter is a char* so it can use the opperator
// defined in our class to place m_ptr on the stack. But in the case of Str
// The compiler does not know what the expected parameter is supposed to be
// so by default it will place the entire class on the stack. In this case
// it would be m_ptr and m_Size.
sprintf( Buf, "Look at some of the data. %s %d %d", (char*) Str, IntArray[3], IntArray[9]);
}

#endif _EXAMPLES_

// -----------------------------------------------------------------------------
#endif // _DYNARRAY_H_