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

Symbian

开发平台:

Visual C++

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