From 614dfefd4902b9824dcf38e3d0e43de09adabce2 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Sat, 11 Dec 2004 02:53:22 +0000 Subject: [PATCH] make buffering optional, to avoid accumulative overhead --- stepmania/src/RageFileBasic.cpp | 87 +++++++++++++++++++++++++-------- stepmania/src/RageFileBasic.h | 50 ++++++++++++++++++- 2 files changed, 115 insertions(+), 22 deletions(-) diff --git a/stepmania/src/RageFileBasic.cpp b/stepmania/src/RageFileBasic.cpp index b6236bfebd..6acdb58dae 100644 --- a/stepmania/src/RageFileBasic.cpp +++ b/stepmania/src/RageFileBasic.cpp @@ -4,6 +4,8 @@ RageFileObj::RageFileObj() { + m_pBuffer = NULL; + ResetBuf(); m_iBufAvail = 0; @@ -11,6 +13,11 @@ RageFileObj::RageFileObj() m_iFilePos = 0; } +RageFileObj::~RageFileObj() +{ + delete [] m_pBuffer; +} + int RageFileObj::Seek( int iOffset ) { m_bEOF = false; @@ -41,26 +48,29 @@ int RageFileObj::Read( void *pBuffer, size_t iBytes ) while( !m_bEOF && iBytes > 0 ) { - /* Copy data out of the buffer first. */ - int FromBuffer = min( (int) iBytes, m_iBufAvail ); - memcpy( pBuffer, m_pBuf, FromBuffer ); + if( m_pBuffer != NULL && m_iBufAvail ) + { + /* Copy data out of the buffer first. */ + int iFromBuffer = min( (int) iBytes, m_iBufAvail ); + memcpy( pBuffer, m_pBuf, iFromBuffer ); - ret += FromBuffer; - m_iFilePos += FromBuffer; - iBytes -= FromBuffer; - m_iBufAvail -= FromBuffer; - m_pBuf += FromBuffer; + ret += iFromBuffer; + m_iFilePos += iFromBuffer; + iBytes -= iFromBuffer; + m_iBufAvail -= iFromBuffer; + m_pBuf += iFromBuffer; - pBuffer = (char *) pBuffer + FromBuffer; + pBuffer = (char *) pBuffer + iFromBuffer; + } if( !iBytes ) break; ASSERT( m_iBufAvail == 0 ); - /* We need more; either fill the buffer and keep going, or just read directly - * into the destination buffer. */ - if( iBytes >= sizeof(m_Buffer) ) + /* If buffering is disabled, or the block is bigger than the buffer, + * read the remainder of the data directly into the desteination buffer. */ + if( m_pBuffer == NULL || iBytes >= BSIZE ) { /* We have a lot more to read, so don't waste time copying it into the * buffer. */ @@ -75,9 +85,10 @@ int RageFileObj::Read( void *pBuffer, size_t iBytes ) return ret; } - m_pBuf = m_Buffer; + /* If buffering is enabled, and we need more data, fill the buffer. */ + m_pBuf = m_pBuffer; int got = FillBuf(); - if( got < 0 ) + if( got == -1 ) return got; if( got == 0 ) m_bEOF = true; @@ -147,6 +158,12 @@ int RageFileObj::Flush() } +void RageFileObj::EnableBuffering() +{ + if( m_pBuffer == NULL ) + m_pBuffer = new char[BSIZE]; +} + /* Read up to the next \n, and return it in out. Strip the \n. If the \n is * preceded by a \r (DOS newline), strip that, too. */ int RageFileObj::GetLine( CString &out ) @@ -156,6 +173,8 @@ int RageFileObj::GetLine( CString &out ) if( m_bEOF ) return 0; + EnableBuffering(); + bool GotData = false; while( 1 ) { @@ -203,8 +222,8 @@ int RageFileObj::GetLine( CString &out ) if( ReAddCR ) { ASSERT( m_iBufAvail == 0 ); - m_pBuf = m_Buffer; - m_Buffer[m_iBufAvail] = '\r'; + m_pBuf = m_pBuffer; + m_pBuffer[m_iBufAvail] = '\r'; ++m_iBufAvail; } @@ -212,7 +231,7 @@ int RageFileObj::GetLine( CString &out ) break; /* We need more data. */ - m_pBuf = m_Buffer; + m_pBuf = m_pBuffer; const int size = FillBuf(); @@ -251,11 +270,14 @@ int RageFileObj::PutLine( const CString &str ) * shouldn't cause the results of AtEOF to change.) */ int RageFileObj::FillBuf() { + /* Don't call this unless buffering is enabled. */ + ASSERT( m_pBuffer != NULL ); + /* The buffer starts at m_Buffer; any data in it starts at m_pBuf; space between * the two is old data that we've read. (Don't mangle that data; we can use it * for seeking backwards.) */ - const int iBufAvail = sizeof(m_Buffer) - (m_pBuf-m_Buffer) - m_iBufAvail; - ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pBuf, m_Buffer, (int) sizeof(m_Buffer) ) ); + const int iBufAvail = BSIZE - (m_pBuf-m_pBuffer) - m_iBufAvail; + ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pBuf, m_pBuffer, (int) BSIZE ) ); const int size = this->ReadInternal( m_pBuf+m_iBufAvail, iBufAvail ); if( size > 0 ) @@ -267,6 +289,31 @@ int RageFileObj::FillBuf() void RageFileObj::ResetBuf() { m_iBufAvail = 0; - m_pBuf = m_Buffer; + m_pBuf = m_pBuffer; } +/* + * Copyright (c) 2003-2004 Glenn Maynard + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + diff --git a/stepmania/src/RageFileBasic.h b/stepmania/src/RageFileBasic.h index 20d1b3a8aa..fb0abd767a 100644 --- a/stepmania/src/RageFileBasic.h +++ b/stepmania/src/RageFileBasic.h @@ -1,3 +1,5 @@ +/* RageFileBasic - simple file interface. */ + #ifndef RAGE_FILE_BASIC_H #define RAGE_FILE_BASIC_H @@ -54,7 +56,7 @@ class RageFileObj: public RageFileBasic { public: RageFileObj(); - virtual ~RageFileObj() { } + virtual ~RageFileObj(); virtual CString GetError() const { return m_sError; } virtual void ClearError() { SetError(""); } @@ -88,6 +90,8 @@ protected: virtual int WriteInternal( const void *pBuffer, size_t iBytes ) = 0; virtual int FlushInternal() { return 0; } + void EnableBuffering(); + void SetError( const CString &sError ) { m_sError = sError; } CString m_sError; @@ -98,11 +102,53 @@ private: bool m_bEOF; int m_iFilePos; + /* + * If buffering is enabled, m_pBuffer is the buffer, m_pBuf is the current read + * position in the buffer and m_iBufAvail is the number of bytes at m_pBuf. Note + * that buffering is only enabled if: + * + * - GetLine() is called (which requires buffering to efficiently search for newlines); + * - or EnableBuffering() is called + * + * Currently, once buffering is enabled, it stays enabled for the life of the + * object. + * + * If buffering is not enabled, this buffer will not be allocated, keeping the + * size overhead of each file down. Layered RageFileBasic implementations, which + * read from other RageFileBasics, should generally not use buffering, in order + * to avoid reads being passed through several buffers, which is only a waste of + * memory. + */ enum { BSIZE = 1024 }; - char m_Buffer[BSIZE]; + char *m_pBuffer; char *m_pBuf; int m_iBufAvail; }; #endif +/* + * Copyright (c) 2003-2004 Glenn Maynard, Chris Danford, Steve Checkoway + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, and/or sell copies of the Software, and to permit persons to + * whom the Software is furnished to do so, provided that the above + * copyright notice(s) and this permission notice appear in all copies of + * the Software and that both the above copyright notice(s) and this + * permission notice appear in supporting documentation. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT + * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ +