cbqueue.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:18k
- /* ***** BEGIN LICENSE BLOCK *****
- * Source last modified: $Id: cbqueue.cpp,v 1.6.32.3 2004/07/09 01:45:59 hubbe Exp $
- *
- * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
- *
- * The contents of this file, and the files included with this file,
- * are subject to the current version of the RealNetworks Public
- * Source License (the "RPSL") available at
- * http://www.helixcommunity.org/content/rpsl unless you have licensed
- * the file under the current version of the RealNetworks Community
- * Source License (the "RCSL") available at
- * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
- * will apply. You may also obtain the license terms directly from
- * RealNetworks. You may not use this file except in compliance with
- * the RPSL or, if you have a valid RCSL with RealNetworks applicable
- * to this file, the RCSL. Please see the applicable RPSL or RCSL for
- * the rights, obligations and limitations governing use of the
- * contents of the file.
- *
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL") in which case the provisions of the GPL are applicable
- * instead of those above. If you wish to allow use of your version of
- * this file only under the terms of the GPL, and not to allow others
- * to use your version of this file under the terms of either the RPSL
- * or RCSL, indicate your decision by deleting the provisions above
- * and replace them with the notice and other provisions required by
- * the GPL. If you do not delete the provisions above, a recipient may
- * use your version of this file under the terms of any one of the
- * RPSL, the RCSL or the GPL.
- *
- * This file is part of the Helix DNA Technology. RealNetworks is the
- * developer of the Original Code and owns the copyrights in the
- * portions it created.
- *
- * This file, and the files included with this file, is distributed
- * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
- * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
- * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
- * ENJOYMENT OR NON-INFRINGEMENT.
- *
- * Technology Compatibility Kit Test Suite(s) Location:
- * http://www.helixcommunity.org/content/tck
- *
- * Contributor(s):
- *
- * ***** END LICENSE BLOCK ***** */
- /*******************************************************************
- *
- * NAME: CBQueue.h
- *
- * CLASS:
- * CByteQueue class declaration.
- *
- * DESCRIPTION:
- * Class declaration for a 'Queue of bytes' object.
- * This object is meant to serve the needs of either clients as
- * an abstract object, or of subclasses as a base object.
- *
- * That is a client may use this instances of this class directly,
- * or they may inherit from the class and provide expanded
- *
- * NOTES:
- * The only time a subclass MUST provide a virtual override
- * is for the GetElementSize() method when the subclass changes
- * the size of queued elements. All other virtual methods
- * provide fully functional default behavior that will ramain
- * functional even when the ElementSize changes.
- *
- * The assignment operator is one of the few cases where a
- * subclass will need to provide new functionality by virtue of
- * inheriting from the base. Subclasses should use the base
- * method for assigning the bits of the base class prior to
- * performing their own assignment related operations.
- *
- *
- *******************************************************************/
- #include "hlxclib/string.h" // for memcpy()
- #include "hxassert.h"
- #include "cbqueue.h"
- #if defined( _WINDOWS ) || defined( _WIN32 )
- #include <stdlib.h> // for __min()
- #endif
- #if !defined( __min )
- #define __min(a,b) (((a) < (b)) ? (a) : (b))
- #endif // !defined( __min )
- #include "hxheap.h"
- #ifdef _DEBUG
- #undef HX_THIS_FILE
- static const char HX_THIS_FILE[] = __FILE__;
- #endif
- /*
- ** CByteQueue::CByteQueue( nSize, nGranularity )
- *
- * PARAMETERS:
- * nSize Number of bytes we want to be able to put in queue
- * nGranularity Make our buffer a multiple of this size.
- * (for subclasses)
- *
- * DESCRIPTION:
- * Parameterized constructor.
- *
- * RETURNS:
- * void
- */
- CByteQueue::CByteQueue( UINT16 nSize, UINT16 nGranularity ) :
- m_pData( 0 ),
- m_pTail( 0 ),
- m_pHead( 0 ),
- m_pMax( 0 ),
- m_nMaxSize(0),
- m_nGranularity( nGranularity )
- {
- HX_ASSERT( this );
- // We add one here because the queue MUST maintain at least one byte
- // free in the allocated buffer (to distinguish full from empty states).
- m_nSize = CByteQueue::Base_GranulatedSize( nSize, nGranularity ) + 1;
- m_pData = new UCHAR[m_nSize];
- if (!m_pData)
- {
- // If we used exceptions, now would be a good time
- // to throw one.
- m_nSize = 0;
- HX_ASSERT( 0 );
- return;
- }
- else
- {
- m_pMax = m_pData + Base_GetBufferSize();
- Base_SetEmpty();
- #if defined( _DEBUG )
- HX_ASSERT( IsQueueValid() );
- // Init our buffer w/ known garbage
- memset( m_pData, 0xfc, Base_GetBufferSize() );
- #endif // _DEBUG
- }
- return;
- } // CByteQueue() - Parameterized constructor
- /*
- ** CByteQueue::CByteQueue( const CByteQueue &rReferent )
- *
- * PARAMETERS:
- * rReferent A constant reference to the object we want to copy.
- *
- * DESCRIPTION:
- * Copy constructor.
- *
- * RETURNS:
- * void
- */
- CByteQueue::CByteQueue( const CByteQueue &rReferent ) :
- m_pData( 0 ),
- m_pTail( 0 ),
- m_pHead( 0 ),
- m_pMax( 0 ),
- m_nSize( 0 ),
- m_nGranularity( 0 ),
- m_nMaxSize(0)
- {
- HX_ASSERT( this );
- // Are we copying ourselves? It's a nop if we are.
- if (&rReferent == this)
- {
- return;
- }
- // Ok, figure out how large a buffer to get and allocate it
- m_pData = new UCHAR[rReferent.Base_GetBufferSize()];
- if (!m_pData)
- {
- // If we had exceptions, now would be a good time
- // to throw one.
- m_nSize = 0;
- HX_ASSERT( 0 );
- return;
- }
- else
- {
- m_nSize = rReferent.Base_GetBufferSize();
- m_pMax = m_pData + Base_GetBufferSize();
- m_nGranularity = rReferent.m_nGranularity;
- // Get a copy of the referent's data into our buffer
- rReferent.Base_PeekBuff( m_pData + 1, Base_GetBufferSize() );
- m_pHead = m_pData;
- m_pTail = m_pData + rReferent.Base_GetUsedByteCount();
- #if defined( _DEBUG )
- HX_ASSERT( IsQueueValid() );
- // Init our buffer w/ known garbage
- memset( m_pData, 0xfc, rReferent.Base_GetBufferSize() );
- #endif // _DEBUG
- }
- return;
- } // CByteQueue() - Copy constructor
- /*
- ** CByteQueue::~CByteQueue()
- *
- * PARAMETERS:
- * void
- *
- * DESCRIPTION:
- * Virtual destructor for the base class.
- *
- * RETURNS:
- * void
- */
- CByteQueue::~CByteQueue()
- {
- HX_ASSERT( this );
- if (m_pData)
- {
- HX_ASSERT( IsQueueValid() );
- delete [] m_pData;
- }
- m_pData = NULL;
- m_pTail = NULL;
- m_pHead = NULL;
- m_pMax = NULL;
- m_nSize = 0;
- m_nGranularity = 0;
- #if defined( _DEBUG )
- memset( this, FILLER_BYTE, sizeof( *this ) );
- #endif
- } // ~CByteQueue() - Destructor
- /*
- ** CByteQueue & CByteQueue::operator=( const CByteQueue &rReferent )
- *
- * PARAMETERS:
- * rReferant Constant reference to an object to assign from (rValue).
- *
- * DESCRIPTION:
- * This is our assignment operator. It assigns from rReferent to
- * an existing object.
- *
- * RETURNS:
- * A reference to ourselves.
- */
- CByteQueue & CByteQueue::operator=( const CByteQueue &rReferent )
- {
- HX_ASSERT( this );
- HX_ASSERT( rReferent.IsQueueValid() );
- HX_ASSERT( &rReferent );
- // Do we need to allocate a new buffer?
- if (rReferent.Base_GetBufferSize() != Base_GetBufferSize())
- {
- // Yes, Allocate the new buffer & copy into it.
- UCHAR * pByte;
- // Ok, figure out how large a buffer to get and allocate it
- pByte = new UCHAR[rReferent.Base_GetBufferSize()];
- if (pByte)
- {
- if (m_pData)
- {
- delete [] m_pData;
- }
- m_pData = NULL;
- m_pData = pByte;
- }
- else
- {
- // Failed buffer allocataion request....
- // It would be nice if we could fail gracefully or throw
- // an exception.
- HX_ASSERT( 0 );
- return( *this );
- }
- }
- // Now need to copy over all of the other elements
- // Or at least set our elements to the correct data
- m_nSize = rReferent.Base_GetBufferSize();
- m_pMax = m_pData + m_nSize;
- m_nGranularity = rReferent.m_nGranularity;
- // Get a copy of the referent's data into our buffer
- rReferent.Base_PeekBuff( m_pData + 1, Base_GetBufferSize() );
- m_pHead = m_pData;
- m_pTail = m_pData + rReferent.Base_GetUsedByteCount();
- HX_ASSERT( IsQueueValid() );
- return( *this );
- } // operator=()
- /*
- ** BOOL CByteQueue::IsQueueValid()
- *
- * PARAMETERS:
- * void
- *
- * DESCRIPTION:
- * This is meant to validate our queue either for debugging
- * purposes, or to ensure a queue was correctly created.
- * (A memory allocation at create time didn't occur).
- *
- * RETURNS:
- * void
- */
- BOOL CByteQueue::IsQueueValid() const
- {
- HX_ASSERT( this );
- // Ensure we have no NULL pointers & we have a size
- if (!m_pData || !m_pTail || !m_pHead || !m_pMax || !m_nSize ||
- !m_nGranularity)
- {
- return( FALSE );
- }
- // Ensure m_pTail is in range
- if (m_pTail < m_pData || m_pTail >= m_pMax)
- {
- return( FALSE );
- }
- // Ensure m_pHead is in range
- if (m_pHead < m_pData || m_pHead >= m_pMax)
- {
- return( FALSE );
- }
- // Ensure m_pMax is the correct value for our size
- if (m_pMax != m_pData + m_nSize)
- {
- return( FALSE );
- }
- // Everything looks good!
- return( TRUE );
- } // IsQueueValid()
- /*
- ** UINT16 CByteQueue::Base_DeQueueBytes( pOutBuffer, nByteCount )
- *
- * PARAMETERS:
- * void *pOutBuffer Pointer to buffer to receive data.
- * UINT16 nAmount Number of bytes desired.
- *
- * DESCRIPTION:
- * Attempts to dequeue nAmount bytes from the Queue and transfers them
- * to pOutBuffer.
- *
- * RETURNS:
- * Number of bytes written to pOutBuffer.
- */
- UINT16 CByteQueue::Base_DeQueueBytes( void *pOutBuffer, UINT16 nByteCount )
- {
- UINT16 nRead;
- HX_ASSERT( this );
- HX_ASSERT( IsQueueValid() );
- HX_ASSERT( pOutBuffer );
- // First read the Queue into pOutBuffer
- nRead = Base_PeekBuff( pOutBuffer, nByteCount );
-
- // Now update m_pHead which is our read pointer
- m_pHead = Base_Normalize( m_pHead, nRead );
- HX_ASSERT( IsQueueValid() );
- return( nRead );
- } // Base_DeQueueBytes()
- void
- CByteQueue::SetMaxSize(UINT16 ulMax)
- {
- m_nMaxSize = ulMax;
- }
- /*
- * Grow the queue to twice its size or at least big enough to hold n more,
- * whichever is greater. returns 1 for good, 0 for bad.
- */
- int
- CByteQueue::Grow(UINT16 nItems)
- {
- //XXXPM Need to check for wrap around on these UINT16s
- if (m_nSize == m_nMaxSize)
- {
- return 0;
- }
- /*
- * Set our initial guess for the new target size by doubling the
- * current size.
- */
- UINT16 ulUsedBytes = Base_GetUsedByteCount();
- UINT16 ulMinFinalCapacity = ulUsedBytes + nItems * GetElementSize() + 1;
- UINT16 ulNewSize;
- // check ulMinFinalCapacity for rollover
- if (ulMinFinalCapacity < m_nSize)
- {
- return 0;
- }
- if (m_nMaxSize && ulMinFinalCapacity > m_nMaxSize)
- {
- return 0;
- }
- for (ulNewSize = 0xFFFF; ulNewSize && (ulNewSize >= ulMinFinalCapacity); ulNewSize = ulNewSize >> 1)
- {
- ;
- }
- if (!ulNewSize)
- return 0;
- ulNewSize = (ulNewSize << 1) + 1;
- if (m_nMaxSize && ulNewSize > m_nMaxSize)
- {
- ulNewSize = m_nMaxSize;
- }
- UCHAR* pNewBuf = new UCHAR[ulNewSize];
- if( !pNewBuf )
- {
- // It would be nice to be able to return HXR_OUTOFMEMORY.
- return 0;
- }
- /*
- * Let the queue copy every thing over for us.
- * +1 because its best to start out with head pointing at 0,
- * and data starting at 1.
- */
- Base_DeQueueBytes((void*)(pNewBuf + 1), ulUsedBytes);
- /*
- * Destroy current structure and re-create with new buffer.
- */
- delete[] m_pData;
- m_pData = pNewBuf;
- m_nSize = ulNewSize;
- //max points one past the end.
- m_pMax = m_pData + m_nSize;
- //head points at spot before first queued data
- m_pHead = m_pData;
- //tail points at last used byte
- m_pTail = m_pData + ulUsedBytes;
- return 1;
- }
- /*
- ** UINT16 CByteQueue::Base_EnQueueBytes( pInBuffer, nByteCount )
- *
- * PARAMETERS:
- * void *pInBuffer Pointer to buffer containing data to EnQueue
- * UINT16 nByteCount Number of bytes items in buffer for EnQueue.
- *
- * DESCRIPTION:
- * Attempts to put nByteCount bytes into queue. If insufficient room, will
- * not enqueue anything.
- *
- * RETURNS:
- * Number of bytes written to pInBuffer.
- * Should be nByteCount or 0 because we fail if we don't have
- * room for ALL data
- */
- UINT16 CByteQueue::Base_EnQueueBytes( void *pInBuffer, UINT16 nByteCount )
- {
- HX_ASSERT( this );
- HX_ASSERT( IsQueueValid() );
- HX_ASSERT( pInBuffer );
- if (!nByteCount || Base_GetAvailableBytes() < nByteCount)
- {
- return( 0 );
- }
- // Ok, we've guaranteed that we have enough room to enqueue nAmount items
- // Now switch on the state of our head & tail pointers
- if (m_pTail < m_pHead)
- {
- // No need to normalize pointers, because we're guaranteed
- // that we have room, hence m_pTail + nAmount HAS to be remain < m_pHead
- // Remember that m_pTail points at the postion just BEFORE our next
- // empty spot in the queue
- memcpy( m_pTail + 1, pInBuffer, nByteCount ); /* Flawfinder: ignore */
- m_pTail += nByteCount;
- }
- else
- {
- // m_pTail >= m_pHead
- // This may require a copy in two passes if we have to wrap around the buffer
- UINT16 nCopy;
- UINT16 nPrevCopy;
- void *pDest;
- // Copying from (m_pTail + 1) to the end of the allocated buffer or nAmount
- // which ever comes first.
- pDest = Base_Normalize( m_pTail, 1);
- nCopy = __min( (UINT16)(m_pMax - (UCHAR *)pDest), nByteCount );
- memcpy( pDest, pInBuffer, nCopy ); /* Flawfinder: ignore */
- m_pTail = (UCHAR *)pDest + nCopy - 1;
- // Figure out how much more we have to copy (if any)
- nPrevCopy = nCopy;
- nCopy = nByteCount - nCopy;
- if (nCopy)
- {
- // Now we're copying into the base of the allocated array
- // whatever we didn't copy the first pass around
- memcpy( m_pData, (UCHAR *)pInBuffer + nPrevCopy, nCopy ); /* Flawfinder: ignore */
- m_pTail = m_pData + nCopy - 1;
- }
- }
- HX_ASSERT( IsQueueValid() );
- return( nByteCount );
- } // Base_EnQueueBytes()
- UINT16 CByteQueue::PeekAt( UINT16 nIndex, void *pOutBuffer ) const
- {
- UINT16 nCopy;
- UINT16 nByteCount;
- void *pHead;
- void *pTail;
- HX_ASSERT( pOutBuffer );
- HX_ASSERT( this );
- HX_ASSERT( IsQueueValid() );
- if (nIndex >= GetQueuedItemCount())
- {
- return( 0 );
- }
- // We don't want to modify m_pTail or m_pHead here, so copy them
- // and use our copies to manipulate the buffer.
- pTail = m_pTail;
- // Advance pHead till it points at the correct position
- // relative to the index we want.
- nByteCount = GetElementSize();
- pHead = Base_Normalize( m_pHead, (nIndex * nByteCount + 1) );
- if (pHead < pTail)
- {
- memcpy( pOutBuffer, (UCHAR *)pHead, nByteCount ); /* Flawfinder: ignore */
- return( nByteCount );
- }
- else
- {
- // pHead > pTail
- UINT16 nPrevCopy;
- // Copying from (pHead + 1) to the end of the allocated buffer or
- // nByteCount which ever comes first.
- nCopy = __min( (UINT16)(m_pMax - (UCHAR *)pHead), nByteCount );
- memcpy( pOutBuffer, pHead, nCopy ); /* Flawfinder: ignore */
-
- // Figure out how much more we have to copy (if any)
- nPrevCopy = nCopy;
- nCopy = nByteCount - nCopy;
- if (nCopy)
- {
- // Now we're copying from the base of the allocated array
- // whatever we didn't copy the first pass around
- memcpy( (UCHAR *)pOutBuffer + nPrevCopy, m_pData, nCopy ); /* Flawfinder: ignore */
- }
- return( nCopy + nPrevCopy );
- }
- }
- /*
- ** UINT16 CByteQueue::Base_PeekBuff( pOutBuffer, nByteCount )
- *
- * PARAMETERS:
- * pOutBuffer Pointer to buffer to receive data in queue.
- * nByteCount Number of bytes to copy out of queue.
- *
- * DESCRIPTION:
- * Private primitive used to copy data out of a queue buffer.
- * This is a workhorse function used in DeQueue(), operator=(),
- * and our copy constructor.
- *
- * RETURNS:
- * The number of bytes copied out of the buffer.
- */
- UINT16 CByteQueue::Base_PeekBuff( void *pOutBuffer, UINT16 nByteCount ) const
- {
- UINT16 nCopy;
- void *pHead;
- void *pTail;
- HX_ASSERT( this );
- HX_ASSERT( IsQueueValid() );
- // if the Queue is empty, then we can't get anything
- if (IsEmpty())
- {
- return( 0 );
- }
- // We don't want to modify m_pTail or m_pHead here, so copy them
- // and use our copies to manipulate the buffer.
- pTail = m_pTail;
- pHead = m_pHead;
- if (pHead < pTail)
- {
- // We can do the copy in one pass w/o having to Normalize() the pointer
- nCopy = __min( nByteCount, Base_GetUsedByteCount() );
- memcpy( pOutBuffer, (UCHAR *)pHead + 1, nCopy ); /* Flawfinder: ignore */
- return( nCopy );
- }
- else
- {
- // pHead > pTail
- UINT16 nPrevCopy;
- UCHAR * pSrc;
- // Copying from (pHead + 1) to the end of the allocated buffer or
- // nByteCount which ever comes first.
- pSrc = Base_Normalize( (UCHAR *)pHead, 1 );
- nCopy = __min( (UINT16)(m_pMax - pSrc), nByteCount );
- memcpy( pOutBuffer, pSrc, nCopy ); /* Flawfinder: ignore */
-
- // The __min() above ensures we don't need to Normalize the pointer
- pHead = pSrc + nCopy - 1;
- // Figure out how much more we have to copy (if any)
- nPrevCopy = nCopy;
- nCopy = nByteCount - nCopy;
- if (nCopy)
- {
- // Now we're copying from the base of the allocated array
- // whatever we didn't copy the first pass around
- memcpy( (UCHAR *)pOutBuffer + nPrevCopy, m_pData, nCopy ); /* Flawfinder: ignore */
- }
- return( nCopy + nPrevCopy );
- }
- } // Base_PeekBuff()