|
|
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Circular Buffer
//
//=============================================================================//
#include "tier0/dbg.h"
#include "tier1/mempool.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 m_nRead;
char *pchDest = (char*)pchDestIn;
nPeeked = Peek(pchDest, nCount);
if (nPeeked != 0) { m_nRead = Advance(nPeeked);
Assert(m_nRead == nPeeked); } else { m_nRead = 0; }
AssertValid(); return(m_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; }
CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 8820 - 1, TSLIST_NODE_ALIGNMENT ), 24> g_SmallBuffers; CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 17640 - 1, TSLIST_NODE_ALIGNMENT ), 44> g_MediumBuffers; CFixedBudgetMemoryPool<ALIGN_VALUE(sizeof( CCircularBuffer ) + 35280 - 1, TSLIST_NODE_ALIGNMENT ), 16> g_LargeBuffers;
CCircularBuffer *AllocateCircularBuffer( int nSize ) { CCircularBuffer *pCCircularBuffer; if ( nSize <= 8820 ) { pCCircularBuffer = (CCircularBuffer *)g_SmallBuffers.Alloc(); } else if ( nSize <= 17640 ) { pCCircularBuffer = (CCircularBuffer *)g_MediumBuffers.Alloc(); } else if ( nSize <= 35280 ) { pCCircularBuffer = (CCircularBuffer *)g_LargeBuffers.Alloc(); } else { pCCircularBuffer = (CCircularBuffer *)malloc( sizeof( CCircularBuffer ) + nSize - 1 ); }
pCCircularBuffer->SetSize( nSize ); return pCCircularBuffer; }
void FreeCircularBuffer( CCircularBuffer *pCircularBuffer ) { int nSize = pCircularBuffer->GetSize();
if ( nSize <= 8820 ) { g_SmallBuffers.Free( pCircularBuffer ); } else if ( nSize <= 17640 ) { g_MediumBuffers.Free( pCircularBuffer ); } else if ( nSize <= 35280 ) { g_LargeBuffers.Free( pCircularBuffer ); } else { free( pCircularBuffer ); } }
|