#ifndef __RingBuffer_h #define __RingBuffer_h #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 /////////////////////////////////////////////////////////////////////////////// // Stardust Namespace /////////////////////////////////////////////////////////////////////////////// namespace Stardust { class CRingBuffer { protected: /////////////////////////////////////////////////////////////////// // Protected Member Variables // char * m_pBuf; char * m_pTmpBuf; // dupe buf for working so no alloc/free while running. int m_nBufSize; // the size of the ring buffer int m_iReadPtr; // the read pointer int m_iWritePtr; // the write pointer public: /////////////////////////////////////////////////////////////////// // Constructor // CRingBuffer() { m_pBuf = NULL; m_pTmpBuf = NULL; m_nBufSize = 0; m_iReadPtr = 0; m_iWritePtr = 0; } /////////////////////////////////////////////////////////////////// // Destructor // virtual ~CRingBuffer() { Destroy(); } /////////////////////////////////////////////////////////////////// // Method: Create // Purpose: Initializes the ring buffer for use. // Parameters: // [in] iBufSize -- maximum size of the ring buffer // Return Value: TRUE if successful, otherwise FALSE. // BOOL Create( int iBufSize ) { BOOL bResult = FALSE; { m_pBuf = new char[ iBufSize ]; if( m_pBuf ) { m_nBufSize = iBufSize; ZeroMemory( m_pBuf, m_nBufSize ); m_pTmpBuf = new char[ iBufSize ]; if( m_pTmpBuf ) { ZeroMemory( m_pTmpBuf, m_nBufSize ); bResult = TRUE; } } } return bResult; } /////////////////////////////////////////////////////////////////// // Method: Destroy // Purpose: Cleans up ring buffer by freeing memory and resetting // member variables to original state. // Parameters: (None) // Return Value: (None) // void Destroy() { if( m_pBuf ) delete m_pBuf; if( m_pTmpBuf ) delete m_pTmpBuf; m_pBuf = NULL; m_pTmpBuf = NULL; m_nBufSize = 0; m_iReadPtr = 0; m_iWritePtr = 0; } /////////////////////////////////////////////////////////////////// // Method: GetMaxReadSize // Purpose: Returns the amount of data (in bytes) available for // reading from the buffer. // Parameters: (None) // Return Value: Amount of data (in bytes) available for reading. // int GetMaxReadSize() { if( m_pBuf ) { if( m_iReadPtr == m_iWritePtr ) return 0; if( m_iReadPtr < m_iWritePtr ) return m_iWritePtr - m_iReadPtr; if( m_iReadPtr > m_iWritePtr ) return (m_nBufSize-m_iReadPtr)+m_iWritePtr; } return 0; } /////////////////////////////////////////////////////////////////// // Method: GetMaxWriteSize // Purpose: Returns the amount of space (in bytes) available for // writing into the buffer. // Parameters: (None) // Return Value: Amount of space (in bytes) available for writing. // int GetMaxWriteSize() { if( m_pBuf ) { if( m_iReadPtr == m_iWritePtr ) return m_nBufSize; if( m_iWritePtr < m_iReadPtr ) return m_iReadPtr - m_iWritePtr; if( m_iWritePtr > m_iReadPtr ) return (m_nBufSize-m_iWritePtr)+m_iReadPtr; } return 0; } /////////////////////////////////////////////////////////////////// // Method: WriteBinary // Purpose: Writes binary data into the ring buffer. // Parameters: // [in] pBuf - Pointer to the data to write. // [in] nBufLen - Size of the data to write (in bytes). // Return Value: TRUE upon success, otherwise FALSE. // BOOL WriteBinary( char * pBuf, int nBufLen ) { BOOL bResult = FALSE; { if( nBufLen < GetMaxWriteSize() ) { // easy case, no wrapping if( m_iWritePtr + nBufLen < m_nBufSize ) { CopyMemory( &m_pBuf[m_iWritePtr], pBuf, nBufLen ); m_iWritePtr += nBufLen; } else // harder case we need to wrap { int iFirstChunkSize = m_nBufSize - m_iWritePtr; int iSecondChunkSize = nBufLen - iFirstChunkSize; CopyMemory( &m_pBuf[m_iWritePtr], pBuf, iFirstChunkSize ); CopyMemory( &m_pBuf[0], &pBuf[iFirstChunkSize], iSecondChunkSize ); m_iWritePtr = iSecondChunkSize; } bResult =TRUE; } } return bResult; } /////////////////////////////////////////////////////////////////// // Method: ReadBinary // Purpose: Reads (and extracts) data from the ring buffer. // Parameters: // [in/out] pBuf - Pointer to where read data will be stored. // [in] nBufLen - Size of the data to be read (in bytes). // Return Value: TRUE upon success, otherwise FALSE. // BOOL ReadBinary( char * pBuf, int nBufLen ) { BOOL bResult = FALSE; { if( nBufLen <= GetMaxReadSize() ) { // easy case, no wrapping if( m_iReadPtr + nBufLen <= m_nBufSize ) { CopyMemory( pBuf, &m_pBuf[m_iReadPtr], nBufLen ); m_iReadPtr += nBufLen; } else // harder case, buffer wraps { int iFirstChunkSize = m_nBufSize - m_iReadPtr; int iSecondChunkSize = nBufLen - iFirstChunkSize; CopyMemory( pBuf, &m_pBuf[m_iReadPtr], iFirstChunkSize ); CopyMemory( &pBuf[iFirstChunkSize], &m_pBuf[0], iSecondChunkSize ); m_iReadPtr = iSecondChunkSize; } bResult =TRUE; } } return bResult; } /////////////////////////////////////////////////////////////////// // Method: PeekChar // Purpose: Peeks at a character at the given position in the ring // buffer, without extracting it. // Parameters: // [in] iPos - Index of the character to peek (zero-based). // [out] ch - The character peeked. // Return Value: TRUE upon success, otherwise FALSE. // BOOL PeekChar( int iPos, char & ch ) { BOOL bResult = FALSE; { if( iPos < GetMaxReadSize() ) { if( m_iWritePtr > m_iReadPtr ) { // easy case, buffer doesn't wrap ch = m_pBuf[ m_iReadPtr+iPos ]; bResult = TRUE; } else if( m_iWritePtr == m_iReadPtr ) { // nothing in the buffer } else if( m_iWritePtr < m_iReadPtr ) { // harder case, buffer wraps if( m_iReadPtr + iPos < m_nBufSize ) { // pos was in first chunk ch = m_pBuf[ m_iReadPtr + iPos ]; bResult = TRUE; } else { // pos is in second chunk ch = m_pBuf[ iPos - (m_nBufSize-m_iReadPtr) ]; bResult = TRUE; } } } } return bResult; } /////////////////////////////////////////////////////////////////// // Method: FindChar // Purpose: Determines if the specified character is in the ring // buffer, and if so, returns the index position. // Parameters: // [in] chLookFor - Character to look for in the ring buffer. // [out] riPos - The index position of the character, if found. // Return Value: TRUE upon success, otherwise FALSE. // BOOL FindChar( char chLookFor, int & riPos ) { BOOL bResult = FALSE; { int iSize = GetMaxReadSize(); for( int i = 0; i < iSize; i++ ) { char ch; if( PeekChar( i, ch ) ) { if( ch == chLookFor ) { riPos = i; bResult = TRUE; break; } } } } return bResult; } /////////////////////////////////////////////////////////////////// // Method: ReadTextLine // Purpose: Reads a line of text from the buffer, if available. // Parameters: // [out] strLine - The line of text. // Return Value: TRUE upon success, otherwise FALSE. // BOOL ReadTextLine( CString & strLine ) { BOOL bResult = FALSE; { int iPos = 0; if( FindChar('/n',iPos) ) { int iSize = iPos+1; if( ReadBinary( m_pTmpBuf, iSize ) ) { m_pTmpBuf[ iSize ] = '/0'; strLine = m_pTmpBuf; bResult = TRUE; } } } return bResult; } }; } // End of Stardust namespace #endif//__RingBuffer_h /////////////////////////////////////////////////////////////////////////////// // End of file ///////////////////////////////////////////////////////////////////////////////