サイクルbufferの実装

3391 ワード

ヘッダファイル:
   
#define SAFE_ARRAY_DELETE(POINTER) if (POINTER) { delete [] POINTER; POINTER = NULL; }
class CCircleBuffer  
{
public:
    // construction / destruction
    CCircleBuffer();
    virtual ~CCircleBuffer();

    // create the buffer
    void CreateBuffer(int nBytes, int nMaxDirectWriteBytes);

    // query
    int MaxAdd();
    int MaxGet();

    // direct writing
    __forceinline unsigned char * CCircleBuffer::GetDirectWritePointer()
    {
        // return a pointer to the tail -- note that it will always be safe to write
        // at least m_nMaxDirectWriteBytes since we use an end cap region
        return &m_pBuffer[m_nTail];
    }

    __forceinline void CCircleBuffer::UpdateAfterDirectWrite(int nBytes)
    {
        // update the tail
        m_nTail += nBytes;

        // if the tail enters the "end cap" area, set the end cap and loop around
        if (m_nTail >= (m_nTotal - m_nMaxDirectWriteBytes))
        {
            m_nEndCap = m_nTail;
            m_nTail = 0;
        }
    }

    // get data
    int Get(unsigned char * pBuffer, int nBytes);

    // remove / empty
    void Empty();
    int RemoveHead(int nBytes);
    int RemoveTail(int nBytes);

private:
    int m_nTotal;
    int m_nMaxDirectWriteBytes;
    int m_nEndCap;
    int m_nHead;
    int m_nTail;
    unsigned char * m_pBuffer;
};

実装:
#include "CircleBuffer.h"

CCircleBuffer::CCircleBuffer()
{
    m_pBuffer = NULL;
    m_nTotal = 0;
    m_nHead = 0;
    m_nTail = 0;
    m_nEndCap = 0;
    m_nMaxDirectWriteBytes = 0;
}

CCircleBuffer::~CCircleBuffer()
{
    SAFE_ARRAY_DELETE(m_pBuffer)
}

void CCircleBuffer::CreateBuffer(int nBytes, int nMaxDirectWriteBytes)
{
    SAFE_ARRAY_DELETE(m_pBuffer)
    
    m_nMaxDirectWriteBytes = nMaxDirectWriteBytes;
    m_nTotal = nBytes + 1 + nMaxDirectWriteBytes;
    m_pBuffer = new unsigned char [m_nTotal];
    m_nHead = 0;
    m_nTail = 0;
    m_nEndCap = m_nTotal;
}

int CCircleBuffer::MaxAdd()
{
    int nMaxAdd = (m_nTail >= m_nHead) ? (m_nTotal - 1 - m_nMaxDirectWriteBytes) - (m_nTail - m_nHead) : m_nHead - m_nTail - 1;
    return nMaxAdd;
}

int CCircleBuffer::MaxGet()
{
    return (m_nTail >= m_nHead) ? m_nTail - m_nHead : (m_nEndCap - m_nHead) + m_nTail;
}

int CCircleBuffer::Get(unsigned char * pBuffer, int nBytes)
{
    int nTotalGetBytes = 0;

    if (pBuffer != NULL && nBytes > 0)
    {
        int nHeadBytes = min(m_nEndCap - m_nHead, nBytes);
        int nFrontBytes = nBytes - nHeadBytes;

        memcpy(&pBuffer[0], &m_pBuffer[m_nHead], nHeadBytes);
        nTotalGetBytes = nHeadBytes;

        if (nFrontBytes > 0)
        {
            memcpy(&pBuffer[nHeadBytes], &m_pBuffer[0], nFrontBytes);
            nTotalGetBytes += nFrontBytes;
        }

        RemoveHead(nBytes);
    }

    return nTotalGetBytes;
}

void CCircleBuffer::Empty()
{
    m_nHead = 0;
    m_nTail = 0;
    m_nEndCap = m_nTotal;
}

int CCircleBuffer::RemoveHead(int nBytes)
{
    nBytes = min(MaxGet(), nBytes);
    m_nHead += nBytes;
    if (m_nHead >= m_nEndCap)
        m_nHead -= m_nEndCap;
    return nBytes;
}

int CCircleBuffer::RemoveTail(int nBytes)
{
    nBytes = min(MaxGet(), nBytes);
    m_nTail -= nBytes;
    if (m_nTail < 0)
        m_nTail += m_nEndCap;
    return nBytes;
}