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

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