//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Circular Buffer // //=============================================================================// #include "tier0/dbg.h" #include "circularbuffer.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" CCircularBuffer::CCircularBuffer() { SetSize( 0 ); } CCircularBuffer::CCircularBuffer(int size) { SetSize(size); } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Sets the maximum size for a circular buffer. This does not do any // memory allocation, it simply informs the buffer of its size. //Author : DSpeyrer //------------------------------------------------------------------------------ void CCircularBuffer::SetSize(int size) { Assert( this ); m_nSize = size; m_nRead = 0; m_nWrite = 0; m_nCount = 0; } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Empties a circular buffer. //Author : DSpeyrer //------------------------------------------------------------------------------ void CCircularBuffer::Flush() { AssertValid(); m_nRead = 0; m_nWrite = 0; m_nCount = 0; } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Returns the available space in a circular buffer. //Author : DSpeyrer //------------------------------------------------------------------------------ int CCircularBuffer::GetWriteAvailable() { AssertValid(); return(m_nSize - m_nCount); } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Returns the size of a circular buffer. //Author : DSpeyrer //------------------------------------------------------------------------------ int CCircularBuffer::GetSize() { AssertValid(); return(m_nSize); } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Returns the number of bytes in a circular buffer. //Author : DSpeyrer //------------------------------------------------------------------------------ int CCircularBuffer::GetReadAvailable() { AssertValid(); return(m_nCount); } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Reads a specified number of bytes from a circular buffer without // consuming them. They will still be available for future calls to // Read or Peek. //Input : pchDest - destination buffer. // m_nCount - number of bytes to place in destination buffer. //Output : Returns the number of bytes placed in the destination buffer. //Author : DSpeyrer //------------------------------------------------------------------------------ int CCircularBuffer::Peek(char *pchDest, int nCount) { // If no data available, just return. if(m_nCount == 0) { return(0); } // // Requested amount should not exceed the available amount. // nCount = MIN(m_nCount, nCount); // // Copy as many of the requested bytes as possible. // If buffer wrap occurs split the data into two chunks. // if (m_nRead + nCount > m_nSize) { int nCount1 = m_nSize - m_nRead; memcpy(pchDest, &m_chData[m_nRead], nCount1); pchDest += nCount1; int nCount2 = nCount - nCount1; memcpy(pchDest, m_chData, nCount2); } // Otherwise copy it in one go. else { memcpy(pchDest, &m_chData[m_nRead], nCount); } AssertValid(); return nCount; } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Advances the read index, consuming a specified number of bytes from // the circular buffer. //Input : m_nCount - number of bytes to consume. //Output : Returns the actual number of bytes consumed. //Author : DSpeyrer //------------------------------------------------------------------------------ int CCircularBuffer::Advance(int nCount) { // If no data available, just return. if (m_nCount == 0) { return(0); } // // Requested amount should not exceed the available amount. // nCount = MIN(m_nCount, nCount); // Advance the read pointer, checking for buffer //wrap. // m_nRead = (m_nRead + nCount) % m_nSize; m_nCount -= nCount; // // If we have emptied the buffer, reset the read and write indices // to minimize buffer wrap. // if (m_nCount == 0) { m_nRead = 0; m_nWrite = 0; } AssertValid(); return nCount; } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Reads a specified number of bytes from a circular buffer. The bytes // will be consumed by the read process. //Input : pchDest - destination buffer. // m_nCount - number of bytes to place in destination buffer. //Output : Returns the number of bytes placed in the destination buffer. //Author : DSpeyrer //------------------------------------------------------------------------------ int CCircularBuffer::Read(void *pchDestIn, int nCount) { int nPeeked; int nRead; char *pchDest = (char*)pchDestIn; nPeeked = Peek(pchDest, nCount); if (nPeeked != 0) { nRead = Advance(nPeeked); assert( nRead == nPeeked); } else { nRead = 0; } AssertValid(); return(nRead); } //------------------ Copyright (c) 1999 Valve, LLC. ---------------------------- //Purpose : Writes a specified number of bytes to the buffer. //Input : pm_chData - buffer containing bytes to bw written. // m_nCount - the number of bytes to write. //Output : Returns the number of bytes written. If there wa insufficient space // to write all requested bytes, the value returned will be less than // the requested amount. //Author : DSpeyrer //------------------------------------------------------------------------------ int CCircularBuffer::Write(void *pData, int nBytesRequested) { // Write all the data. int nBytesToWrite = nBytesRequested; char *pDataToWrite = (char*)pData; while(nBytesToWrite) { int from = m_nWrite; int to = m_nWrite + nBytesToWrite; if(to >= m_nSize) { to = m_nSize; } memcpy(&m_chData[from], pDataToWrite, to - from); pDataToWrite += to - from; m_nWrite = to % m_nSize; nBytesToWrite -= to - from; } // Did it cross the read pointer? Then slide the read pointer up. // This way, we will discard the old data. if(nBytesRequested > (m_nSize - m_nCount)) { m_nCount = m_nSize; m_nRead = m_nWrite; } else { m_nCount += nBytesRequested; } AssertValid(); return nBytesRequested; } CCircularBuffer *AllocateCircularBuffer( int nSize ) { char *pBuff = (char *)malloc( sizeof( CCircularBuffer ) + nSize - 1 ); CCircularBuffer *pCCircularBuffer = (CCircularBuffer *)pBuff; pCCircularBuffer->SetSize( nSize ); return pCCircularBuffer; } void FreeCircularBuffer( CCircularBuffer *pCircularBuffer ) { free( (char*)pCircularBuffer ); }