258 lines
5.8 KiB
C++
258 lines
5.8 KiB
C++
#include "stdafx.h"
|
|
#include "CircularBuffer.h"
|
|
|
|
/** Constructor
|
|
*/
|
|
CircularBuffer::CircularBuffer()
|
|
{
|
|
m_buffer = m_bufferEnd = m_regionAPointer = m_regionBPointer = nullptr;
|
|
m_regionASize = m_regionBSize = 0;
|
|
}
|
|
|
|
/** Destructor
|
|
*/
|
|
CircularBuffer::~CircularBuffer()
|
|
{
|
|
free(m_buffer);
|
|
}
|
|
|
|
/** Read bytes from the buffer
|
|
* @param destination pointer to destination where bytes will be written
|
|
* @param bytes number of bytes to read
|
|
* @return true if there was enough data, false otherwise
|
|
*/
|
|
bool CircularBuffer::Read(void * destination, size_t bytes)
|
|
{
|
|
// copy as much out of region a
|
|
size_t cnt = bytes;
|
|
size_t aRead = 0, bRead = 0;
|
|
if( (m_regionASize + m_regionBSize) < bytes )
|
|
return false;
|
|
|
|
// If we have both region A and region B, always "finish" off region A first, as
|
|
// this will contain the "oldest" data
|
|
if( m_regionASize > 0 )
|
|
{
|
|
aRead = (cnt > m_regionASize) ? m_regionASize : cnt;
|
|
memcpy(destination, m_regionAPointer, aRead);
|
|
m_regionASize -= aRead;
|
|
m_regionAPointer += aRead;
|
|
cnt -= aRead;
|
|
}
|
|
|
|
// Data left over? read the data from buffer B
|
|
if( cnt > 0 && m_regionBSize > 0 )
|
|
{
|
|
bRead = (cnt > m_regionBSize) ? m_regionBSize : cnt;
|
|
memcpy((char*)destination + aRead, m_regionBPointer, bRead);
|
|
m_regionBSize -= bRead;
|
|
m_regionBPointer += bRead;
|
|
cnt -= bRead;
|
|
}
|
|
|
|
// is buffer A empty? move buffer B to buffer A, to increase future performance
|
|
if( m_regionASize == 0 )
|
|
{
|
|
if( m_regionBSize > 0 )
|
|
{
|
|
// push it all to the start of the buffer.
|
|
if( m_regionBPointer != m_buffer )
|
|
memmove(m_buffer, m_regionBPointer, m_regionBSize);
|
|
|
|
m_regionAPointer = m_buffer;
|
|
m_regionASize = m_regionBSize;
|
|
m_regionBPointer = nullptr;
|
|
m_regionBSize = 0;
|
|
}
|
|
else
|
|
{
|
|
// no data in region b
|
|
m_regionBPointer = nullptr;
|
|
m_regionBSize = 0;
|
|
m_regionAPointer = m_buffer;
|
|
m_regionASize = 0;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CircularBuffer::AllocateB()
|
|
{
|
|
//printf("[allocating B]\n");
|
|
m_regionBPointer = m_buffer;
|
|
}
|
|
|
|
/** Write bytes to the buffer
|
|
* @param data pointer to the data to be written
|
|
* @param bytes number of bytes to be written
|
|
* @return true if was successful, otherwise false
|
|
*/
|
|
bool CircularBuffer::Write(const void * data, size_t bytes)
|
|
{
|
|
// If buffer B exists, write to it.
|
|
if( m_regionBPointer != nullptr )
|
|
{
|
|
if( GetBFreeSpace() < bytes )
|
|
return false;
|
|
|
|
memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
|
|
m_regionBSize += bytes;
|
|
return true;
|
|
}
|
|
|
|
// Otherwise, write to buffer A, or initialize buffer B depending on which has more space.
|
|
if( GetAFreeSpace() < GetSpaceBeforeA() )
|
|
{
|
|
AllocateB();
|
|
if( GetBFreeSpace() < bytes )
|
|
return false;
|
|
|
|
memcpy(&m_regionBPointer[m_regionBSize], data, bytes);
|
|
m_regionBSize += bytes;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
if( GetAFreeSpace() < bytes )
|
|
return false;
|
|
|
|
memcpy(&m_regionAPointer[m_regionASize], data, bytes);
|
|
m_regionASize += bytes;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/** Returns the number of available bytes left.
|
|
*/
|
|
size_t CircularBuffer::GetSpace()
|
|
{
|
|
if( m_regionBPointer != nullptr )
|
|
return GetBFreeSpace();
|
|
else
|
|
{
|
|
// would allocating buffer B get us more data?
|
|
if( GetAFreeSpace() < GetSpaceBeforeA() )
|
|
{
|
|
AllocateB();
|
|
return GetBFreeSpace();
|
|
}
|
|
|
|
// or not?
|
|
return GetAFreeSpace();
|
|
}
|
|
}
|
|
|
|
/** Returns the number of bytes currently stored in the buffer.
|
|
*/
|
|
size_t CircularBuffer::GetSize()
|
|
{
|
|
return m_regionASize + m_regionBSize;
|
|
}
|
|
|
|
/** Returns the number of contiguous bytes (that can be pushed out in one operation)
|
|
*/
|
|
size_t CircularBuffer::GetContiguousBytes()
|
|
{
|
|
if( m_regionASize ) // A before B
|
|
return m_regionASize;
|
|
else
|
|
return m_regionBSize;
|
|
}
|
|
|
|
/** Removes len bytes from the front of the buffer
|
|
* @param len the number of bytes to "cut"
|
|
*/
|
|
void CircularBuffer::Remove(size_t len)
|
|
{
|
|
// remove from A first before we remove from b
|
|
size_t cnt = len;
|
|
size_t aRem, bRem;
|
|
|
|
// If we have both region A and region B, always "finish" off region A first, as
|
|
// this will contain the "oldest" data
|
|
if( m_regionASize > 0 )
|
|
{
|
|
aRem = (cnt > m_regionASize) ? m_regionASize : cnt;
|
|
m_regionASize -= aRem;
|
|
m_regionAPointer += aRem;
|
|
cnt -= aRem;
|
|
}
|
|
|
|
// Data left over? cut the data from buffer B
|
|
if( cnt > 0 && m_regionBSize > 0 )
|
|
{
|
|
bRem = (cnt > m_regionBSize) ? m_regionBSize : cnt;
|
|
m_regionBSize -= bRem;
|
|
m_regionBPointer += bRem;
|
|
cnt -= bRem;
|
|
}
|
|
|
|
// is buffer A empty? move buffer B to buffer A, to increase future performance
|
|
if( m_regionASize == 0 )
|
|
{
|
|
if( m_regionBSize > 0 )
|
|
{
|
|
// push it all to the start of the buffer.
|
|
if( m_regionBPointer != m_buffer )
|
|
memmove(m_buffer, m_regionBPointer, m_regionBSize);
|
|
|
|
m_regionAPointer = m_buffer;
|
|
m_regionASize = m_regionBSize;
|
|
m_regionBPointer = nullptr;
|
|
m_regionBSize = 0;
|
|
}
|
|
else
|
|
{
|
|
// no data in region b
|
|
m_regionBPointer = nullptr;
|
|
m_regionBSize = 0;
|
|
m_regionAPointer = m_buffer;
|
|
m_regionASize = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Returns a pointer at the "end" of the buffer, where new data can be written
|
|
*/
|
|
void * CircularBuffer::GetBuffer()
|
|
{
|
|
if( m_regionBPointer != nullptr )
|
|
return m_regionBPointer + m_regionBSize;
|
|
else
|
|
return m_regionAPointer + m_regionASize;
|
|
}
|
|
|
|
/** Allocate the buffer with room for size bytes
|
|
* @param size the number of bytes to allocate
|
|
*/
|
|
void CircularBuffer::Allocate(size_t size)
|
|
{
|
|
m_buffer = (uint8*)malloc(size);
|
|
m_bufferEnd = m_buffer + size;
|
|
m_regionAPointer = m_buffer; // reset A to the start
|
|
m_bufferSize = size;
|
|
}
|
|
|
|
/** Increments the "writen" pointer forward len bytes
|
|
* @param len number of bytes to step
|
|
*/
|
|
void CircularBuffer::IncrementWritten(size_t len) // known as "commit"
|
|
{
|
|
if( m_regionBPointer != nullptr )
|
|
m_regionBSize += len;
|
|
else
|
|
m_regionASize += len;
|
|
|
|
}
|
|
|
|
/** Returns a pointer at the "beginning" of the buffer, where data can be pulled from
|
|
*/
|
|
void * CircularBuffer::GetBufferStart()
|
|
{
|
|
if( m_regionASize > 0 )
|
|
return m_regionAPointer;
|
|
else
|
|
return m_regionBPointer;
|
|
|
|
} |