cbbqueue.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:16k
源码类别:

Symbian

开发平台:

C/C++

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