Click here to Skip to main content
15,887,350 members
Articles / Programming Languages / C++
Article

A circular character buffer

Rate me:
Please Sign up or sign in to vote.
2.00/5 (1 vote)
9 Dec 1999 91.1K   1.5K   27   7
A circular, thread-safe read/write character buffer
  • Download demo project - 11 Kb
  • I recently needed a class that stored a character array as a circular buffer. If you are unfamiliar with circular buffer, it is a permanently allocated buffer that has both a read and write position. I have done a few of them in the past, but had lost all of my examples. So I wrote a new one and placed it into a class called CircularBuffer. The CircularBuffer can be read from and written to, and it has methods to get the read and write count. As the buffer is written to the write position increases til the end of the buffer is reached, at that point the write position is wrapped back to the start of the buffer and writing starts from there. The same happens to the read operation also, but the read position is incremented. It is important to note that the read position will never be greater than the write position, since if it were we would be reading data that had not been written to the buffer. Likewise, the write position will never wrap the read position otherwise data that had not been read would be overwritten.

    The basic operations are read and write, both fail if an overlap condition could occur.

    To get the number of availible characters to read the readCount method is used. If the count is greater than zero use the read method to get the latest contents written into the buffer.

    I have included a small test application in a project TestQue. The test driver is in the TestQue.cpp. It is multithreaded win32 console app developed using VC6.

    The CircularBuffer code is in CicularBuffer.cpp and h.

    License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here


    Written By
    United States United States
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

    Comments and Discussions

     
    GeneralA circular buffer that can grow or decrease Pin
    UDria4-Dec-01 0:01
    UDria4-Dec-01 0:01 
    GeneralRe: A circular buffer that can grow or decrease Pin
    moshe beeri22-May-05 2:45
    moshe beeri22-May-05 2:45 
    QuestionCircular Buffer code... another little error in code? Pin
    Bruno Gallichand15-Sep-00 8:24
    sussBruno Gallichand15-Sep-00 8:24 
    AnswerRe: Circular Buffer code... another little error in code? Pin
    Bruno Gallichand15-Sep-00 8:31
    sussBruno Gallichand15-Sep-00 8:31 
    AnswerRe: Circular Buffer code... another little error in code? Pin
    20-Dec-00 7:28
    suss20-Dec-00 7:28 
    Generalbugs Pin
    Fred Huang6-Sep-00 11:54
    Fred Huang6-Sep-00 11:54 
    GeneralRe: bugs Pin
    jm.alkema2-Feb-06 3:09
    jm.alkema2-Feb-06 3:09 
    Fred,

    Hopefully better source code.

    Greetings Jan Marco

    // inc read/write pos based
    // on operation
    bool CircularBuffer::incPos ( long inc, long op )
    {
    long * pos = NULL;
    long lenToEnd = 0;
    // if inc > que size stop
    if ( inc < 0 || inc > m_queSz )
    {
    return false;
    }
    // get pos to modify
    pos = &m_write;
    if ( op == idRead )
    {
    pos = &m_read;
    }
    // get len to que end
    lenToEnd = lengthToEnd(op);

    // if inc not beyond que end
    if ( inc <= lenToEnd )
    {
    *pos += inc;
    }
    else
    {
    // set pos to length from start
    // because of wrap
    *pos = inc - lenToEnd;

    // could set wrap event here
    }

    // if either pos has wrapped to other
    if ( m_read == m_write )
    {
    m_wrapType = idWriteWrap;
    if ( op == idRead )
    {
    m_wrapType = idReadWrap;
    }
    }
    else
    {
    m_wrapType = idNoWrap;
    }

    if (m_read == m_queSz)
    {
    if (m_write == m_queSz)
    {
    m_read = 0;
    m_write = 0;
    }
    else
    {
    m_read = 0;
    }
    }

    return true;
    }

    bool CircularBuffer::read ( BYTE * data, long length )
    {
    long lenRemaining = 0;
    long lenToEnd = 0;

    // show data block to long
    if ( length < 0 || length > m_queSz )
    {
    memset(data, 0, length);
    return false;
    }
    // set read lock
    if ( !m_lock.lock() )
    {
    memset(data, 0, length);
    return false;
    }

    // read length to que end
    lenToEnd = lengthToEnd(idRead);

    if (lenToEnd >= length)
    {
    if ((m_read+length) <= m_write)
    {
    if (length > 0 )
    {
    memcpy(data, &m_que[m_read], length);
    // inc read pos
    incPos( length, idRead );
    }
    }
    else
    {
    if ((m_write < m_read))
    {
    if (length > 0 )
    {
    memcpy(data, &m_que[m_read], length);
    incPos( length, idRead );
    }
    }
    else
    {
    //buffer is empty
    memset(data, 0, length);
    m_lock.unlock();
    return false;
    }
    }
    }
    else
    {
    lenRemaining = length - lenToEnd;
    if ((m_write < m_read) && (m_write >=lenRemaining))
    {
    if (lenToEnd > 0 )
    {
    memcpy(data, &m_que[m_read], lenToEnd );
    }

    if (lenRemaining > 0 )
    {
    memcpy(&data[lenToEnd], &m_que[0], lenRemaining );
    }
    incPos( length, idRead );
    }
    else
    {
    //buffer is empty
    memset(data, 0, length);
    m_lock.unlock();
    return false;
    }
    }

    m_lock.unlock();
    return true;
    }


    bool CircularBuffer::write ( BYTE * data, long length )
    {
    long lenRemaining = 0;
    long lenToEnd = 0;

    // show data block to long
    if ( length < 0 || length > m_queSz )
    {
    return false;
    }
    // wait for write lock
    if ( !m_lock.lock() )
    {
    return false;
    }
    // read length to que end

    lenToEnd = lengthToEnd(idWrite);

    if (lenToEnd >= length)
    {
    if ((m_read <= m_write) || ( (m_write+length) <= m_read))
    {
    memcpy( &m_que[m_write], data, length);
    incPos( length, idWrite );
    }
    else
    { //buffer is full
    }
    }
    else
    {
    lenRemaining = length - lenToEnd;
    if ((m_read <= m_write) && (m_read >=lenRemaining))
    {
    if (lenToEnd > 0 )
    {
    memcpy(&m_que[m_write], data, lenToEnd );
    }

    if (lenRemaining > 0 )
    {
    memcpy(&m_que[0], &data[lenToEnd], lenRemaining );
    }
    incPos( length, idWrite );
    }
    else
    {
    //buffer is full
    }
    }

    m_lock.unlock();

    // set recieve event
    m_rxEvent.set();

    return true;
    }

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.