cbqueue.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:18k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: cbqueue.cpp,v 1.6.32.3 2004/07/09 01:45:59 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. /*******************************************************************
  50.  *
  51.  * NAME: CBQueue.h
  52.  *
  53.  * CLASS:
  54.  * CByteQueue class declaration.
  55.  *
  56.  * DESCRIPTION:
  57.  * Class declaration for a 'Queue of bytes' object.
  58.  * This object is meant to serve the needs of either clients as
  59.  * an abstract object, or of subclasses as a base object.
  60.  *
  61.  * That is a client may use this instances of this class directly,
  62.  * or they may inherit from the class and provide expanded
  63.  *
  64.  * NOTES:
  65.  * The only time a subclass MUST provide a virtual override
  66.  * is for the GetElementSize() method when the subclass changes
  67.  * the size of queued elements.  All other virtual methods
  68.  * provide fully functional default behavior that will ramain
  69.  * functional even when the ElementSize changes.
  70.  *
  71.  * The assignment operator is one of the few cases where a
  72.  * subclass will need to provide new functionality by virtue of
  73.  * inheriting from the base.  Subclasses should use the base
  74.  * method for assigning the bits of the base class prior to
  75.  * performing their own assignment related operations.
  76.  *
  77.  *
  78.  *******************************************************************/
  79. #include "hlxclib/string.h" // for memcpy()
  80. #include "hxassert.h"
  81. #include "cbqueue.h"
  82. #if defined( _WINDOWS ) || defined( _WIN32 )
  83. #include <stdlib.h> // for __min()
  84. #endif
  85. #if !defined( __min )
  86. #define __min(a,b)  (((a) < (b)) ? (a) : (b))
  87. #endif // !defined( __min )
  88. #include "hxheap.h"
  89. #ifdef _DEBUG
  90. #undef HX_THIS_FILE
  91. static const char HX_THIS_FILE[] = __FILE__;
  92. #endif  
  93.  /*
  94.  ** CByteQueue::CByteQueue( nSize, nGranularity )
  95.  *
  96.  *  PARAMETERS:
  97.  * nSize Number of bytes we want to be able to put in queue
  98.  * nGranularity Make our buffer a multiple of this size.
  99.  * (for subclasses)
  100.  *
  101.  *  DESCRIPTION:
  102.  * Parameterized constructor.
  103.  *
  104.  *  RETURNS:
  105.  * void
  106.  */
  107. CByteQueue::CByteQueue( UINT16 nSize, UINT16 nGranularity ) :
  108. m_pData( 0 ),
  109. m_pTail( 0 ),
  110. m_pHead( 0 ),
  111. m_pMax( 0 ),
  112. m_nMaxSize(0),
  113. m_nGranularity( nGranularity )
  114. {
  115. HX_ASSERT( this );
  116. // We add one here because the queue MUST maintain at least one byte
  117. // free in the allocated buffer (to distinguish full from empty states).
  118. m_nSize = CByteQueue::Base_GranulatedSize( nSize, nGranularity ) + 1;
  119. m_pData = new UCHAR[m_nSize];
  120. if (!m_pData)
  121. {
  122. // If we used exceptions, now would be a good time
  123. // to throw one.
  124. m_nSize = 0;
  125. HX_ASSERT( 0 );
  126. return;
  127. }
  128. else
  129. {
  130. m_pMax = m_pData + Base_GetBufferSize();
  131. Base_SetEmpty();
  132. #if defined( _DEBUG )
  133. HX_ASSERT( IsQueueValid() );
  134. // Init our buffer w/ known garbage
  135. memset( m_pData, 0xfc, Base_GetBufferSize() );
  136. #endif // _DEBUG
  137. }
  138. return;
  139. } // CByteQueue() - Parameterized constructor
  140. /*
  141.  ** CByteQueue::CByteQueue( const CByteQueue &rReferent )
  142.  *
  143.  *  PARAMETERS:
  144.  * rReferent A constant reference to the object we want to copy.
  145.  *
  146.  *  DESCRIPTION:
  147.  * Copy constructor.
  148.  *
  149.  *  RETURNS:
  150.  * void
  151.  */
  152. CByteQueue::CByteQueue( const CByteQueue &rReferent ) :
  153. m_pData( 0 ),
  154. m_pTail( 0 ),
  155. m_pHead( 0 ),
  156. m_pMax( 0 ),
  157. m_nSize( 0 ),
  158. m_nGranularity( 0 ),
  159. m_nMaxSize(0)
  160. {
  161. HX_ASSERT( this );
  162. // Are we copying ourselves?  It's a nop if we are.
  163. if (&rReferent == this)
  164. {
  165. return;
  166. }
  167. // Ok, figure out how large a buffer to get and allocate it
  168. m_pData = new UCHAR[rReferent.Base_GetBufferSize()];
  169. if (!m_pData)
  170. {
  171. // If we had exceptions, now would be a good time
  172. // to throw one.
  173. m_nSize = 0;
  174. HX_ASSERT( 0 );
  175. return;
  176. }
  177. else
  178. {
  179. m_nSize = rReferent.Base_GetBufferSize();
  180. m_pMax = m_pData + Base_GetBufferSize();
  181. m_nGranularity = rReferent.m_nGranularity;
  182. // Get a copy of the referent's data into our buffer
  183. rReferent.Base_PeekBuff( m_pData + 1, Base_GetBufferSize() );
  184. m_pHead = m_pData;
  185. m_pTail = m_pData + rReferent.Base_GetUsedByteCount();
  186. #if defined( _DEBUG )
  187. HX_ASSERT( IsQueueValid() );
  188. // Init our buffer w/ known garbage
  189. memset( m_pData, 0xfc, rReferent.Base_GetBufferSize() );
  190. #endif // _DEBUG
  191. }
  192. return;
  193. } // CByteQueue() - Copy constructor
  194. /*
  195.  ** CByteQueue::~CByteQueue()
  196.  *
  197.  *  PARAMETERS:
  198.  * void
  199.  *
  200.  *  DESCRIPTION:
  201.  * Virtual destructor for the base class.
  202.  *
  203.  *  RETURNS:
  204.  * void
  205.  */
  206. CByteQueue::~CByteQueue()
  207. {
  208. HX_ASSERT( this );
  209. if (m_pData)
  210. {
  211. HX_ASSERT( IsQueueValid() );    
  212. delete [] m_pData;
  213. }
  214. m_pData = NULL;
  215. m_pTail = NULL;
  216. m_pHead = NULL;
  217. m_pMax = NULL;
  218. m_nSize = 0;
  219. m_nGranularity = 0;
  220. #if defined( _DEBUG )
  221. memset( this, FILLER_BYTE, sizeof( *this ) );
  222. #endif
  223. } // ~CByteQueue() - Destructor
  224. /*
  225.  ** CByteQueue & CByteQueue::operator=( const CByteQueue &rReferent )
  226.  *
  227.  *  PARAMETERS:
  228.  * rReferant Constant reference to an object to assign from (rValue).
  229.  *
  230.  *  DESCRIPTION:
  231.  * This is our assignment operator.  It assigns from rReferent to
  232.  * an existing object.
  233.  *
  234.  *  RETURNS:
  235.  * A reference to ourselves.
  236.  */
  237. CByteQueue & CByteQueue::operator=( const CByteQueue &rReferent )
  238. {
  239. HX_ASSERT( this );
  240. HX_ASSERT( rReferent.IsQueueValid() );
  241. HX_ASSERT( &rReferent );
  242. // Do we need to allocate a new buffer?
  243. if (rReferent.Base_GetBufferSize() != Base_GetBufferSize())
  244. {
  245. // Yes, Allocate the new buffer & copy into it.
  246. UCHAR * pByte;
  247. // Ok, figure out how large a buffer to get and allocate it
  248. pByte = new UCHAR[rReferent.Base_GetBufferSize()];
  249. if (pByte)
  250. {
  251. if (m_pData)
  252. {
  253. delete [] m_pData;
  254. }
  255. m_pData = NULL;
  256. m_pData = pByte;
  257. }
  258. else
  259. {
  260. // Failed buffer allocataion request....
  261. // It would be nice if we could fail gracefully or throw
  262. // an exception.
  263. HX_ASSERT( 0 );
  264. return( *this );
  265. }
  266. }
  267. // Now need to copy over all of the other elements
  268. // Or at least set our elements to the correct data
  269. m_nSize = rReferent.Base_GetBufferSize();
  270. m_pMax = m_pData + m_nSize;
  271. m_nGranularity = rReferent.m_nGranularity;
  272. // Get a copy of the referent's data into our buffer
  273. rReferent.Base_PeekBuff( m_pData + 1, Base_GetBufferSize() );
  274. m_pHead = m_pData;
  275. m_pTail = m_pData + rReferent.Base_GetUsedByteCount();
  276. HX_ASSERT( IsQueueValid() );    
  277. return( *this );
  278. } // operator=()
  279. /*
  280.  ** BOOL CByteQueue::IsQueueValid()
  281.  *
  282.  *  PARAMETERS:
  283.  * void
  284.  *
  285.  *  DESCRIPTION:
  286.  * This is meant to validate our queue either for debugging
  287.  * purposes, or to ensure a queue was correctly created.
  288.  * (A memory allocation at create time didn't occur).
  289.  *
  290.  *  RETURNS:
  291.  * void
  292.  */
  293. BOOL CByteQueue::IsQueueValid() const
  294. {
  295. HX_ASSERT( this );
  296. // Ensure we have no NULL pointers & we have a size
  297. if (!m_pData || !m_pTail || !m_pHead || !m_pMax || !m_nSize ||
  298.  !m_nGranularity)
  299. {
  300. return( FALSE );
  301. }
  302. // Ensure m_pTail is in range
  303. if (m_pTail < m_pData || m_pTail >= m_pMax)
  304. {
  305. return( FALSE );
  306. }
  307. // Ensure m_pHead is in range
  308. if (m_pHead < m_pData || m_pHead >= m_pMax)
  309. {
  310. return( FALSE );
  311. }
  312. // Ensure m_pMax is the correct value for our size
  313. if (m_pMax != m_pData + m_nSize)
  314. {
  315. return( FALSE );
  316. }
  317.     // Everything looks good!
  318. return( TRUE );
  319. } // IsQueueValid()
  320. /*
  321.  ** UINT16 CByteQueue::Base_DeQueueBytes( pOutBuffer, nByteCount )
  322.  *
  323.  *  PARAMETERS:
  324.  * void  *pOutBuffer Pointer  to buffer to receive data.
  325.  * UINT16 nAmount Number of bytes desired.
  326.  *
  327.  *  DESCRIPTION:
  328.  * Attempts to dequeue nAmount bytes from the Queue and transfers them 
  329.  * to pOutBuffer.
  330.  *
  331.  *  RETURNS:
  332.  * Number of bytes written to pOutBuffer.
  333.  */
  334. UINT16 CByteQueue::Base_DeQueueBytes( void *pOutBuffer, UINT16 nByteCount )
  335. {
  336. UINT16 nRead;
  337. HX_ASSERT( this );
  338. HX_ASSERT( IsQueueValid() );
  339. HX_ASSERT( pOutBuffer );
  340. // First read the Queue into pOutBuffer
  341. nRead = Base_PeekBuff( pOutBuffer, nByteCount );
  342. // Now update m_pHead which is our read pointer
  343. m_pHead = Base_Normalize( m_pHead, nRead );
  344. HX_ASSERT( IsQueueValid() );
  345. return( nRead );
  346. } // Base_DeQueueBytes()
  347. void
  348. CByteQueue::SetMaxSize(UINT16 ulMax)
  349. {
  350.     m_nMaxSize = ulMax;
  351. }
  352. /*
  353.  * Grow the queue to twice its size or at least big enough to hold n more,
  354.  * whichever is greater.  returns 1 for good, 0 for bad.
  355.  */
  356. int
  357. CByteQueue::Grow(UINT16 nItems)
  358. {
  359.     //XXXPM Need to check for wrap around on these UINT16s
  360.     if (m_nSize == m_nMaxSize)
  361.     {
  362. return 0;
  363.     }
  364.     /*
  365.      * Set our initial guess for the new target size by doubling the
  366.      * current size.
  367.      */
  368.     UINT16 ulUsedBytes = Base_GetUsedByteCount();
  369.     UINT16 ulMinFinalCapacity = ulUsedBytes  + nItems * GetElementSize() + 1;
  370.     UINT16 ulNewSize;
  371.     // check ulMinFinalCapacity for rollover 
  372.     if (ulMinFinalCapacity < m_nSize)
  373.     {
  374. return 0;
  375.     }
  376.     if (m_nMaxSize && ulMinFinalCapacity > m_nMaxSize)
  377.     {
  378. return 0;
  379.     }
  380.     for (ulNewSize = 0xFFFF; ulNewSize && (ulNewSize >= ulMinFinalCapacity); ulNewSize = ulNewSize >> 1)
  381.     {
  382. ;
  383.     }
  384.     if (!ulNewSize)
  385.         return 0;
  386.     ulNewSize = (ulNewSize << 1) + 1;
  387.     if (m_nMaxSize && ulNewSize > m_nMaxSize)
  388.     {
  389. ulNewSize = m_nMaxSize;
  390.     }
  391.     UCHAR* pNewBuf = new UCHAR[ulNewSize];
  392.     if( !pNewBuf )
  393.     {
  394.         // It would be nice to be able to return HXR_OUTOFMEMORY.
  395.         return 0;
  396.     }
  397.     /*
  398.      * Let the queue copy every thing over for us.
  399.      * +1 because its best to start out with head pointing at 0,
  400.      * and data starting at 1.
  401.      */
  402.     Base_DeQueueBytes((void*)(pNewBuf + 1), ulUsedBytes);
  403.     /*
  404.      * Destroy current structure and re-create with new buffer.
  405.      */
  406.     delete[] m_pData;
  407.     m_pData = pNewBuf;
  408.     m_nSize = ulNewSize;
  409.     //max points one past the end.
  410.     m_pMax = m_pData + m_nSize;
  411.     //head points at spot before first queued data
  412.     m_pHead = m_pData;
  413.     //tail points at last used byte
  414.     m_pTail = m_pData + ulUsedBytes;
  415.     return 1;
  416. }
  417. /*
  418.  ** UINT16 CByteQueue::Base_EnQueueBytes( pInBuffer, nByteCount )
  419.  *
  420.  *  PARAMETERS:
  421.  * void *pInBuffer Pointer to buffer containing data to EnQueue
  422.  * UINT16 nByteCount Number of bytes items in buffer for EnQueue.
  423.  *
  424.  *  DESCRIPTION:
  425.  * Attempts to put nByteCount bytes into queue.  If insufficient room, will
  426.  * not enqueue anything.
  427.  *
  428.  *  RETURNS:
  429.  * Number of bytes written to pInBuffer.
  430.  * Should be nByteCount or 0 because we fail if we don't have 
  431.  * room for ALL data
  432.  */
  433. UINT16 CByteQueue::Base_EnQueueBytes( void *pInBuffer, UINT16 nByteCount )
  434. {
  435. HX_ASSERT( this );
  436. HX_ASSERT( IsQueueValid() );
  437. HX_ASSERT( pInBuffer );
  438. if (!nByteCount || Base_GetAvailableBytes() < nByteCount)
  439. {
  440. return( 0 );
  441. }
  442. // Ok, we've guaranteed that we have enough room to enqueue nAmount items
  443. // Now switch on the state of our head & tail pointers
  444. if (m_pTail < m_pHead)
  445. {
  446. // No need to normalize pointers, because we're guaranteed
  447. // that we have room, hence m_pTail + nAmount HAS to be remain < m_pHead
  448. // Remember that m_pTail points at the postion just BEFORE our next
  449. // empty spot in the queue
  450. memcpy( m_pTail + 1, pInBuffer, nByteCount ); /* Flawfinder: ignore */
  451. m_pTail += nByteCount;
  452. }
  453. else
  454. {
  455. // m_pTail >= m_pHead
  456. // This may require a copy in two passes if we have to wrap around the buffer
  457. UINT16 nCopy;
  458. UINT16 nPrevCopy;
  459. void *pDest;
  460. // Copying from (m_pTail + 1) to the end of the allocated buffer or nAmount
  461. // which ever comes first.
  462. pDest = Base_Normalize( m_pTail, 1);
  463. nCopy = __min( (UINT16)(m_pMax - (UCHAR *)pDest), nByteCount );
  464. memcpy( pDest, pInBuffer, nCopy ); /* Flawfinder: ignore */
  465. m_pTail = (UCHAR *)pDest + nCopy - 1;
  466. // Figure out how much more we have to copy (if any)
  467. nPrevCopy = nCopy;
  468. nCopy = nByteCount - nCopy;
  469. if (nCopy)
  470. {
  471. // Now we're copying into the base of the allocated array
  472. // whatever we didn't copy the first pass around
  473. memcpy( m_pData, (UCHAR *)pInBuffer + nPrevCopy, nCopy ); /* Flawfinder: ignore */
  474. m_pTail = m_pData + nCopy - 1;
  475. }
  476. }
  477. HX_ASSERT( IsQueueValid() );
  478. return( nByteCount );
  479. } // Base_EnQueueBytes()
  480. UINT16 CByteQueue::PeekAt( UINT16 nIndex, void *pOutBuffer ) const
  481. {
  482. UINT16 nCopy;
  483. UINT16 nByteCount;
  484. void *pHead;
  485. void *pTail;
  486. HX_ASSERT( pOutBuffer );
  487. HX_ASSERT( this );
  488. HX_ASSERT( IsQueueValid() );
  489. if (nIndex >= GetQueuedItemCount())
  490. {
  491. return( 0 );
  492. }
  493. // We don't want to modify m_pTail or m_pHead here, so copy them
  494. // and use our copies to manipulate the buffer.
  495. pTail = m_pTail;
  496. // Advance pHead till it points at the correct position
  497. // relative to the index we want.
  498. nByteCount = GetElementSize();
  499. pHead = Base_Normalize( m_pHead,  (nIndex * nByteCount + 1) );
  500. if (pHead < pTail)
  501. {
  502. memcpy( pOutBuffer, (UCHAR *)pHead, nByteCount ); /* Flawfinder: ignore */
  503. return( nByteCount );
  504. }
  505. else
  506. {
  507. // pHead > pTail
  508. UINT16 nPrevCopy;
  509. // Copying from (pHead + 1) to the end of the allocated buffer or
  510. // nByteCount which ever comes first.
  511. nCopy = __min( (UINT16)(m_pMax - (UCHAR *)pHead), nByteCount );
  512. memcpy( pOutBuffer, pHead, nCopy ); /* Flawfinder: ignore */
  513. // Figure out how much more we have to copy (if any)
  514. nPrevCopy = nCopy;
  515. nCopy = nByteCount - nCopy;
  516. if (nCopy)
  517. {
  518. // Now we're copying from the base of the allocated array
  519. // whatever we didn't copy the first pass around
  520. memcpy( (UCHAR *)pOutBuffer + nPrevCopy, m_pData, nCopy ); /* Flawfinder: ignore */
  521. }
  522. return( nCopy + nPrevCopy );
  523. }
  524. }
  525. /*
  526.  ** UINT16 CByteQueue::Base_PeekBuff( pOutBuffer, nByteCount )
  527.  *
  528.  *  PARAMETERS:
  529.  * pOutBuffer Pointer to buffer to receive data in queue.
  530.  * nByteCount Number of bytes to copy out of queue.
  531.  *
  532.  *  DESCRIPTION:
  533.  * Private primitive used to copy data out of a queue buffer.
  534.  * This is a workhorse function used in DeQueue(), operator=(),
  535.  * and our copy constructor.
  536.  *
  537.  *  RETURNS:
  538.  * The number of bytes copied out of the buffer.
  539.  */
  540. UINT16 CByteQueue::Base_PeekBuff( void *pOutBuffer, UINT16 nByteCount ) const
  541. {
  542. UINT16 nCopy;
  543. void *pHead;
  544. void *pTail;
  545. HX_ASSERT( this );
  546. HX_ASSERT( IsQueueValid() );    
  547. // if the Queue is empty, then we can't get anything
  548. if (IsEmpty())
  549. {
  550. return( 0 );
  551. }
  552. // We don't want to modify m_pTail or m_pHead here, so copy them
  553. // and use our copies to manipulate the buffer.
  554. pTail = m_pTail;
  555. pHead = m_pHead;
  556. if (pHead < pTail)
  557. {
  558. // We can do the copy in one pass w/o having to Normalize() the pointer
  559. nCopy = __min( nByteCount, Base_GetUsedByteCount() );
  560. memcpy( pOutBuffer, (UCHAR *)pHead + 1, nCopy ); /* Flawfinder: ignore */
  561. return( nCopy );
  562. }
  563. else
  564. {
  565. // pHead > pTail
  566. UINT16 nPrevCopy;
  567. UCHAR * pSrc;
  568. // Copying from (pHead + 1) to the end of the allocated buffer or
  569. // nByteCount which ever comes first.
  570. pSrc = Base_Normalize( (UCHAR *)pHead, 1 );
  571. nCopy = __min( (UINT16)(m_pMax - pSrc), nByteCount );
  572. memcpy( pOutBuffer, pSrc, nCopy ); /* Flawfinder: ignore */
  573. // The __min() above ensures we don't need to Normalize the pointer
  574. pHead = pSrc + nCopy - 1;
  575. // Figure out how much more we have to copy (if any)
  576. nPrevCopy = nCopy;
  577. nCopy = nByteCount - nCopy;
  578. if (nCopy)
  579. {
  580. // Now we're copying from the base of the allocated array
  581. // whatever we didn't copy the first pass around
  582. memcpy( (UCHAR *)pOutBuffer + nPrevCopy, m_pData, nCopy ); /* Flawfinder: ignore */
  583. }
  584. return( nCopy + nPrevCopy );
  585. }
  586. } // Base_PeekBuff()