1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2025-01-09 10:39:03 +08:00
hl2sdk/public/tier1/circularbuffer.h

160 lines
4.0 KiB
C++

#ifndef CIRCULARBUFFER_H
#define CIRCULARBUFFER_H
#ifdef _WIN32
#pragma once
#endif
class CCircularBuffer
{
public:
// Creates circular buffer that works as a FIFO, it would wrap the buffer once it reaches it's size
// and overwrite past data.
DLL_CLASS_IMPORT CCircularBuffer();
// Creates circular buffer that works as a FIFO and allocates a buffer of a size nSize (would use 64 if nSize is less than that),
// it would wrap the buffer once it reaches it's size and overwrite past data.
DLL_CLASS_IMPORT CCircularBuffer( uint32 nSize );
DLL_CLASS_IMPORT ~CCircularBuffer();
// Resizes internal buffer with nSize size, using 0 as a size would free up the buffer
DLL_CLASS_IMPORT void Resize( int nSize );
// Peeks into a buffer and writes to pOut without consuming bytes,
// number of bytes written is returned
DLL_CLASS_IMPORT int Peek( void *pOut, int nCount );
// Reads from the buffer to pOut and consumes bytes,
// number of bytes written is returned
DLL_CLASS_IMPORT int Read( void *pOut, int nCount );
// Consumes nCount bytes from the buffer
DLL_CLASS_IMPORT int Advance( int nCount );
// Clears the internal buffer
DLL_CLASS_IMPORT void Flush();
// Writes from pData nCount bytes to buffer, leaving it ready for reading
DLL_CLASS_IMPORT int Write( const void *pData, int nCount );
// Writes zeroed nCount bytes of data to buffer, leaving it ready for reading
DLL_CLASS_IMPORT int WriteZeroed( int nCount );
int GetSize() const { return m_nSize; }
int GetReadAvailable() const { return m_nCount; }
int GetWriteAvailable() const { return m_nSize - m_nCount; }
protected:
DLL_CLASS_IMPORT void AssertValid();
private:
int m_nCount;
int m_nRead;
int m_nWrite;
int m_nSize;
void *m_pData;
};
template <typename T, int ELEMENT_COUNT, typename I = int>
class CFixedSizeCircularBuffer
{
public:
// Creates a circular buffer of a certain type, the buffer works as a LIFO
CFixedSizeCircularBuffer() : m_Data(), m_nIndex( 0 ), m_nCount( 0 ) {}
// Called when a new element is written to a buffer
virtual void ElementAlloc( T &element ) = 0;
// Called when element is about to be consumed from the buffer
virtual void ElementRelease( T &element ) = 0;
I GetReadAvailable() const { return m_nCount; }
I GetWriteAvailable() const { return ELEMENT_COUNT - m_nCount; }
// Peeks and reads from the buffer but not consumes from it.
// Offset could be used to iterate the available for read entries in the buffer.
// If peek was successful true is returned and data is written to out.
bool Peek( T *out, I offset = 0 )
{
if(m_nCount == 0 || offset < 0 || offset >= m_nCount || !out)
return false;
*out = m_Data[(m_nIndex + (m_nCount - 1) - offset) % ELEMENT_COUNT];
return true;
}
// Consumes nCount entries in the buffer, releasing the consumed elements
// number of consumed items is returned.
I Advance( I nCount )
{
if(m_nCount == 0)
return 0;
if(nCount < m_nCount)
{
for(I i = 0; i < nCount; i++)
{
ElementRelease( m_Data[(m_nIndex + (m_nCount - 1) - i) % ELEMENT_COUNT] );
}
m_nCount -= nCount;
}
else
{
if(m_nCount > 0)
{
for(I i = 0; i < m_nCount; i++)
{
ElementRelease( m_Data[(m_nIndex + i) % ELEMENT_COUNT] );
}
}
m_nIndex = 0;
m_nCount = 0;
}
return MIN( nCount, m_nCount );
}
// Reads from the buffer and consumes if there are entries to read,
// true is returned if operation was successful and out is filled with the data.
bool Read( T *out )
{
if(!Peek( out ))
return false;
Advance( 1 );
return true;
}
// Writes to a buffer and makes the data read ready
void Write( T &data )
{
if(m_nCount == ELEMENT_COUNT)
{
ElementRelease( m_Data[m_nIndex] );
ElementAlloc( m_Data[m_nIndex] );
m_Data[m_nIndex] = data;
m_nIndex = (m_nIndex + 1) % ELEMENT_COUNT;
}
else
{
I idx = (m_nIndex + m_nCount) % ELEMENT_COUNT;
ElementAlloc( m_Data[idx] );
m_Data[idx] = data;
m_nCount++;
}
}
private:
T m_Data[ELEMENT_COUNT];
I m_nIndex;
I m_nCount;
};
#endif /* CIRCULARBUFFER_H */