make buffering optional, to avoid accumulative overhead
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
RageFileObj::RageFileObj()
|
RageFileObj::RageFileObj()
|
||||||
{
|
{
|
||||||
|
m_pBuffer = NULL;
|
||||||
|
|
||||||
ResetBuf();
|
ResetBuf();
|
||||||
|
|
||||||
m_iBufAvail = 0;
|
m_iBufAvail = 0;
|
||||||
@@ -11,6 +13,11 @@ RageFileObj::RageFileObj()
|
|||||||
m_iFilePos = 0;
|
m_iFilePos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RageFileObj::~RageFileObj()
|
||||||
|
{
|
||||||
|
delete [] m_pBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
int RageFileObj::Seek( int iOffset )
|
int RageFileObj::Seek( int iOffset )
|
||||||
{
|
{
|
||||||
m_bEOF = false;
|
m_bEOF = false;
|
||||||
@@ -41,26 +48,29 @@ int RageFileObj::Read( void *pBuffer, size_t iBytes )
|
|||||||
|
|
||||||
while( !m_bEOF && iBytes > 0 )
|
while( !m_bEOF && iBytes > 0 )
|
||||||
{
|
{
|
||||||
/* Copy data out of the buffer first. */
|
if( m_pBuffer != NULL && m_iBufAvail )
|
||||||
int FromBuffer = min( (int) iBytes, m_iBufAvail );
|
{
|
||||||
memcpy( pBuffer, m_pBuf, FromBuffer );
|
/* Copy data out of the buffer first. */
|
||||||
|
int iFromBuffer = min( (int) iBytes, m_iBufAvail );
|
||||||
|
memcpy( pBuffer, m_pBuf, iFromBuffer );
|
||||||
|
|
||||||
ret += FromBuffer;
|
ret += iFromBuffer;
|
||||||
m_iFilePos += FromBuffer;
|
m_iFilePos += iFromBuffer;
|
||||||
iBytes -= FromBuffer;
|
iBytes -= iFromBuffer;
|
||||||
m_iBufAvail -= FromBuffer;
|
m_iBufAvail -= iFromBuffer;
|
||||||
m_pBuf += FromBuffer;
|
m_pBuf += iFromBuffer;
|
||||||
|
|
||||||
pBuffer = (char *) pBuffer + FromBuffer;
|
pBuffer = (char *) pBuffer + iFromBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
if( !iBytes )
|
if( !iBytes )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ASSERT( m_iBufAvail == 0 );
|
ASSERT( m_iBufAvail == 0 );
|
||||||
|
|
||||||
/* We need more; either fill the buffer and keep going, or just read directly
|
/* If buffering is disabled, or the block is bigger than the buffer,
|
||||||
* into the destination buffer. */
|
* read the remainder of the data directly into the desteination buffer. */
|
||||||
if( iBytes >= sizeof(m_Buffer) )
|
if( m_pBuffer == NULL || iBytes >= BSIZE )
|
||||||
{
|
{
|
||||||
/* We have a lot more to read, so don't waste time copying it into the
|
/* We have a lot more to read, so don't waste time copying it into the
|
||||||
* buffer. */
|
* buffer. */
|
||||||
@@ -75,9 +85,10 @@ int RageFileObj::Read( void *pBuffer, size_t iBytes )
|
|||||||
return ret;
|
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();
|
int got = FillBuf();
|
||||||
if( got < 0 )
|
if( got == -1 )
|
||||||
return got;
|
return got;
|
||||||
if( got == 0 )
|
if( got == 0 )
|
||||||
m_bEOF = true;
|
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
|
/* 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. */
|
* preceded by a \r (DOS newline), strip that, too. */
|
||||||
int RageFileObj::GetLine( CString &out )
|
int RageFileObj::GetLine( CString &out )
|
||||||
@@ -156,6 +173,8 @@ int RageFileObj::GetLine( CString &out )
|
|||||||
if( m_bEOF )
|
if( m_bEOF )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
EnableBuffering();
|
||||||
|
|
||||||
bool GotData = false;
|
bool GotData = false;
|
||||||
while( 1 )
|
while( 1 )
|
||||||
{
|
{
|
||||||
@@ -203,8 +222,8 @@ int RageFileObj::GetLine( CString &out )
|
|||||||
if( ReAddCR )
|
if( ReAddCR )
|
||||||
{
|
{
|
||||||
ASSERT( m_iBufAvail == 0 );
|
ASSERT( m_iBufAvail == 0 );
|
||||||
m_pBuf = m_Buffer;
|
m_pBuf = m_pBuffer;
|
||||||
m_Buffer[m_iBufAvail] = '\r';
|
m_pBuffer[m_iBufAvail] = '\r';
|
||||||
++m_iBufAvail;
|
++m_iBufAvail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +231,7 @@ int RageFileObj::GetLine( CString &out )
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
/* We need more data. */
|
/* We need more data. */
|
||||||
m_pBuf = m_Buffer;
|
m_pBuf = m_pBuffer;
|
||||||
|
|
||||||
const int size = FillBuf();
|
const int size = FillBuf();
|
||||||
|
|
||||||
@@ -251,11 +270,14 @@ int RageFileObj::PutLine( const CString &str )
|
|||||||
* shouldn't cause the results of AtEOF to change.) */
|
* shouldn't cause the results of AtEOF to change.) */
|
||||||
int RageFileObj::FillBuf()
|
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 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
|
* the two is old data that we've read. (Don't mangle that data; we can use it
|
||||||
* for seeking backwards.) */
|
* for seeking backwards.) */
|
||||||
const int iBufAvail = sizeof(m_Buffer) - (m_pBuf-m_Buffer) - m_iBufAvail;
|
const int iBufAvail = BSIZE - (m_pBuf-m_pBuffer) - m_iBufAvail;
|
||||||
ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pBuf, m_Buffer, (int) sizeof(m_Buffer) ) );
|
ASSERT_M( iBufAvail >= 0, ssprintf("%p, %p, %i", m_pBuf, m_pBuffer, (int) BSIZE ) );
|
||||||
const int size = this->ReadInternal( m_pBuf+m_iBufAvail, iBufAvail );
|
const int size = this->ReadInternal( m_pBuf+m_iBufAvail, iBufAvail );
|
||||||
|
|
||||||
if( size > 0 )
|
if( size > 0 )
|
||||||
@@ -267,6 +289,31 @@ int RageFileObj::FillBuf()
|
|||||||
void RageFileObj::ResetBuf()
|
void RageFileObj::ResetBuf()
|
||||||
{
|
{
|
||||||
m_iBufAvail = 0;
|
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
/* RageFileBasic - simple file interface. */
|
||||||
|
|
||||||
#ifndef RAGE_FILE_BASIC_H
|
#ifndef RAGE_FILE_BASIC_H
|
||||||
#define RAGE_FILE_BASIC_H
|
#define RAGE_FILE_BASIC_H
|
||||||
|
|
||||||
@@ -54,7 +56,7 @@ class RageFileObj: public RageFileBasic
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RageFileObj();
|
RageFileObj();
|
||||||
virtual ~RageFileObj() { }
|
virtual ~RageFileObj();
|
||||||
|
|
||||||
virtual CString GetError() const { return m_sError; }
|
virtual CString GetError() const { return m_sError; }
|
||||||
virtual void ClearError() { SetError(""); }
|
virtual void ClearError() { SetError(""); }
|
||||||
@@ -88,6 +90,8 @@ protected:
|
|||||||
virtual int WriteInternal( const void *pBuffer, size_t iBytes ) = 0;
|
virtual int WriteInternal( const void *pBuffer, size_t iBytes ) = 0;
|
||||||
virtual int FlushInternal() { return 0; }
|
virtual int FlushInternal() { return 0; }
|
||||||
|
|
||||||
|
void EnableBuffering();
|
||||||
|
|
||||||
void SetError( const CString &sError ) { m_sError = sError; }
|
void SetError( const CString &sError ) { m_sError = sError; }
|
||||||
CString m_sError;
|
CString m_sError;
|
||||||
|
|
||||||
@@ -98,11 +102,53 @@ private:
|
|||||||
bool m_bEOF;
|
bool m_bEOF;
|
||||||
int m_iFilePos;
|
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 };
|
enum { BSIZE = 1024 };
|
||||||
char m_Buffer[BSIZE];
|
char *m_pBuffer;
|
||||||
char *m_pBuf;
|
char *m_pBuf;
|
||||||
int m_iBufAvail;
|
int m_iBufAvail;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user