//
//  Copyright (c) 2001, Reson, Inc. All Rights Reserved.
//
//  Filename:   CDynamicBuffer.h
//
//  Project:    6046
//
//  Author(s):  W. Arcus
//
//  Purpose:    Defines and implements the template class for CDynamicBuffer<>.
//
//  Notes:      
//

#if !defined(AFX_DYNAMICBUFFER_H__805D1B66_AAC6_4297_A3CF_FA39AC7D3443__INCLUDED_)
#define AFX_DYNAMICBUFFER_H__805D1B66_AAC6_4297_A3CF_FA39AC7D3443__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

template <class tElementType>
class CDynamicBuffer
{
private:

    // Attributes.

    unsigned long                   m_ulAllocatedSize;
    unsigned long                   m_ulElementsStored;

    tElementType                   *m_ptStorage;

    // Services.

    void                            ReallocateStorage   (   const unsigned long                &rulMinSize );

public:

    // Services.
                                    CDynamicBuffer      (   const unsigned long                &rulSize     = 128UL * 1024UL );

                                    CDynamicBuffer      (   const CDynamicBuffer<tElementType> &rRhs );
    virtual                        ~CDynamicBuffer      (   void );

    CDynamicBuffer<tElementType> &  operator =          (   const CDynamicBuffer<tElementType> &rRhs );

    tElementType *                  GetAt               (   const unsigned long                &rulIndex    = 0UL ) const;
    tElementType                    operator []         (   const unsigned long                &rulIndex )          const;

    unsigned long                   Size                (   void ) const;

    bool                            Add                 (   const tElementType                 *ptItemsToAdd,
                                                            const unsigned long                &rulNumberToAdd );

    void                            Reset               (   const bool                         &bZeroMemory = false );

};

template <class tElementType>
void CDynamicBuffer<tElementType>::ReallocateStorage( const unsigned long &rulMinSize )
{
    // Double the storage allocated.

    const unsigned long  ulNewSize = 2 * rulMinSize;
    tElementType        *ptStorage = new tElementType [ ulNewSize ];

    ASSERT( ptStorage != NULL );

    if ( ptStorage != NULL )
    {
        // Copy over the previous data to the new buffer.

        ::memcpy( &ptStorage[ 0 ], &m_ptStorage[ 0 ], sizeof( tElementType ) * m_ulElementsStored );

        // Destroy the old allocated buffer.

        delete [] m_ptStorage;

        // Assign the storage pointer to the new allocated area and adjust the allocated size indicator.

        m_ptStorage       = ptStorage;
        m_ulAllocatedSize = ulNewSize;
    }
}

template <class tElementType>
CDynamicBuffer<tElementType>::CDynamicBuffer( const unsigned long &rulSize )
{
    ASSERT( rulSize > 0UL );
    m_ptStorage = new tElementType [ rulSize ];

    m_ulAllocatedSize  = rulSize;
    m_ulElementsStored = 0UL;
}

template <class tElementType>
CDynamicBuffer<tElementType>::CDynamicBuffer( const CDynamicBuffer<tElementType> &rRhs )
{
    m_ptStorage = new tElementType [ rRhs.m_ulAllocatedSize ];

    ASSERT( m_ptStorage != NULL );

    // Copy the bytes.

    ::memcpy( m_ptStorage, rRhs.m_ptStorage, sizeof( tElementType ) * rRhs.m_ulElementsStored );

    // Set the size attributes.

    m_ulAllocatedSize  = rRhs.m_ulAllocatedSize;
    m_ulElementsStored = rRhs.m_ulElementsStored;
}

template <class tElementType>
CDynamicBuffer<tElementType>::~CDynamicBuffer( void )
{
    if ( m_ptStorage != NULL )
    {
        delete [] m_ptStorage;
        m_ptStorage = NULL;
    }

    m_ulAllocatedSize  = 0UL;
    m_ulElementsStored = 0UL;
}

template <class tElementType>
CDynamicBuffer<tElementType> & CDynamicBuffer<tElementType>::operator = ( const CDynamicBuffer<tElementType> &rRhs )
{
    m_ptStorage = new tElementType [ rRhs.m_ulAllocatedSize ];

    ASSERT( m_ptStorage != NULL );

    // Copy the bytes.

    ::memcpy( m_ptStorage, rRhs.m_ptStorage, sizeof( tElementType ) * rRhs.m_ulElementsStored );

    // Set the size attributes.

    m_ulAllocatedSize  = rRhs.m_ulAllocatedSize;
    m_ulElementsStored = rRhs.m_ulElementsStored;

    return *this;
}

template <class tElementType>
tElementType * CDynamicBuffer<tElementType>::GetAt( const unsigned long &rulIndex ) const
{
    ASSERT( rulIndex < m_ulElementsStored );

    return &m_ptStorage[ rulIndex ];
}

template <class tElementType>
tElementType CDynamicBuffer<tElementType>::operator [] ( const unsigned long &rulIndex ) const
{
    ASSERT( rulIndex < m_ulElementsStored );

    return m_ptStorage[ rulIndex ];
}

template <class tElementType>
unsigned long CDynamicBuffer<tElementType>::Size( void ) const
{
    return m_ulElementsStored;
}

template <class tElementType>
bool CDynamicBuffer<tElementType>::Add( const tElementType *ptItemsToAdd, const unsigned long &rulNumberToAdd )
{
    bool bSuccess = false;

    try
    {
        ASSERT( ptItemsToAdd != NULL );

        if ( rulNumberToAdd > 0UL )
        {
            ASSERT( m_ptStorage != NULL );

            const unsigned long ulMinRequiredStorage = m_ulElementsStored + rulNumberToAdd;

            if ( ulMinRequiredStorage > m_ulAllocatedSize )
            {
                ReallocateStorage( ulMinRequiredStorage );
            }

            ::memcpy( &m_ptStorage[ m_ulElementsStored ], ptItemsToAdd, rulNumberToAdd * sizeof( tElementType ) );

            m_ulElementsStored += rulNumberToAdd;
        }

        bSuccess = true;
    }
    catch ( ... )
    {
        bSuccess = false;
    }

    return bSuccess;
}

template <class tElementType>
void CDynamicBuffer<tElementType>::Reset( const bool &rbZeroMemory )
{
    m_ulElementsStored = 0UL;

    if ( rbZeroMemory )
    {
        ::memset( m_ptStorage, 0x00, sizeof( tElementType ) * m_ulAllocatedSize );
    }
}

#endif // !defined(AFX_DYNAMICBUFFER_H__805D1B66_AAC6_4297_A3CF_FA39AC7D3443__INCLUDED_)
